from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from dateutil.parser import parse
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from dateutil import parser
import os
from pandas.plotting import register_matplotlib_converters
import np_financial
register_matplotlib_converters()
Hanesbrands Inc. (HBI)
Last update: 12 April 2023
annual report: 2021
share price data from: 4/20/2022
Last update: 28 Nov 2023
This page is a test post. The Jupyter notebook is a rough draft. So far I like how Quarto renders JupyterLab notebooks to HTML. This post is for testing only.
\(\Large {\color {red} {\text {update dates and stock history before publishing}}}\)
- finish the narrative
- make updates to template
- delet notes and raw cells
- update share price, intrest rates, price history, adjust narrative
- publish
Use this file. Some edits were made in the HPL folder.
Write this up as a case study.
In Feb 2023 HBI anounced end of dividends and stock fell from \$8.78 to \$6.20, now trades at \$4.91.
https://www.fool.com/investing/2023/02/03/hanesbrands-drops-its-dividend-as-times-get-tough/
https://www.yahoo.com/now/hanesbrands-plunges-gloomy-outlook-dividend-152149039.html
https://www.dividendpower.org/2023/03/10/hanesbrands-hbi-dividend-cut-to-zero/
Is this now a value stock?
451 shares
Date | Quantity | Price |
---|---|---|
09/01/2022 | 116 | 8.595 |
06/16/2022 | 110 | 9.71 |
05/02/2022 | 153 | 13.1199 |
04/20/2022 | 72 | 14.6763 |
weighted average cost
\((116*8.595+110*9.71+153*13.1199+72*14.6763)/(116+110+153+72) = 11.372856541019958\)
Total cost basis
\((116*8.595+110*9.71+153*13.1199+72*14.6763) = 5129.158300000001\)
number of shares
\((116+110+153+72) = 451\)
current value 2,214
Hold stock for now since intrinic value is above current price.
Data from May 3, 2023
\(\Large {\color {red} {\text {Note}}}\)
exporting to MD for offline editing, files to bring for ASUS
- MD file - HTML and convert to pdf - annual report - compustat report
Hanesbrands Inc. (HBI)
$ 5.16
Previous Close 4.91
Open 5.10
Bid 4.96 x 3200
Ask 4.97 x 27000
Day's Range 4.97 - 5.29
52 Week Range 4.73 - 14.19
Volume 948,323
Avg. Volume 11,934,518
Market Cap 1.803B
Beta (5Y Monthly) 1.58
PE Ratio (TTM) N/A
EPS (TTM) -0.38
Earnings Date May 03, 2023
Forward Dividend & Yield N/A (N/A)
Ex-Dividend Date Nov 21, 2022
1y Target Est 5.21
Stock price from 4/20/2022
14.66
Symbol: HBI
Security Description: Hanesbrands Inc
Action: BOUGHT
Security No./CUSIP: 410345-10-2
Type: Cash
Trade Date: 04/20/22
Settle Date: 04/22/22
Quantity Price Principal Charges and/or Interest Total Amount
72 $14.6763 $1,056.69
N/A
$1,056.69
Abstract
This notebook presents analysis and commentary for HanesBrands (NYSE: HBI). The analysis presented is based on examination of the business fundamentals. A discount cash flow analysis is used to estimate the intrinsic value of the company. A second evaluation method based on earnings history and historical price to earnings ratio is calculated. Using some judgment calls, as explained in the analysis, an intrinsic stock value is calculated. Some shares of HBI were purchased based on dividend yield and the intrinsic stock value. As described in the analysis, HBI suspended the dividend in order to direct funds to pay down the debt. Since the company is not paying a dividend, does it make sense to hold the company as a value stock? The analysis concludes that there is some merit to think the company might be a value stock, but as a non-dividend paying stock, having HBI does not fit my investment goals of holding quality dividend paying stocks.
At the time of writing this report, some stock analysis were suggesting that HBI might be a value play, that is, buying this stock on the cheap and holding until the price recovers or the dividend is re-instated. See the articles here and here. My analysis shown below indicates that the even if NOP can be increased over time by 10%, the ratio of NOP to total liabilities remains above 7. (need to recalculate projected total liabilities and clean up the analysis). Historically the ratio was near 5 when HBI initiated their dividend.
Introduction
Shares of HBI were purchased based on dividend yield and intrinsic value of the company. The dividend yield at the time of purchase was running about 4%. I currently hold 451 shares and my purchase history is:
Date | Quantity | Price |
---|---|---|
04/20/2022 | 72 | \$14.67 |
05/02/2022 | 153 | \$13.11 |
06/16/2022 | 110 | \$9.71 |
09/01/2022 | 116 | \$8.595 |
My weighted average cost is \$11.372 per share and my cost basis is \$5,129.16. The current value of my shares are \$2,214, a loss of about 57%. If I hold the shares until September of 2023, all the shares will be long term capital losses.
Since HBI has canceled the dividend payments, should this stock be retained for its value or for possible restoration of dividends? The most recent financial results for the quarter ending are shown in the current news section below.
Company description
Hanesbrands Inc. is an American multinational clothing company based in Winston-Salem, North Carolina. It employs 65,300 people internationally. On September 6, 2006, the company and several brands were spun off by the Sara Lee Corporation. Hanesbrands owns several clothing brands, including Hanes, Champion, Playtex, Bali, L’eggs, Just My Size, Barely There, Wonderbra, Maidenform, Berlei, and Bonds.
Hanesbrands Inc., a Maryland corporation, is a consumer goods company with a portfolio of leading apparel brands, including Hanes, Champion, Bonds, Maidenform, Bali, Playtex, Bras N Things, JMS/Just My Size, Gear for Sports, Wonderbra, Berlei, Comfortwash, and Alternative. The Company designs, manufactures, sources and sells a broad range of basic apparel such as T-shirts, bras, panties, shapewear, underwear, socks and activewear. The Company’s fiscal year ends on the Saturday closest to December 31. All references to “2022”, “2021” and “2020” relate to the 52-week fiscal year ended on December 31, 2022 and January 1, 2022, and the 53-week fiscal year ended on January 2, 2021, respectively. Two subsidiaries of the Company close one day after the Company’s consolidated year end. The difference in reporting of financial information for these subsidiaries did not have a material impact on the Company’s financial condition, results of operations or cash flows.
In late 2020, the Company undertook a comprehensive global business review focused on building consumer-centric growth. The review resulted in the Company’s Full Potential plan, which is its multi-year growth strategy that focuses on four pillars to drive growth and enhance long-term profitability and identifies the initiatives to unlock growth. The Company’s four pillars of growth are to grow the Champion brand globally, drive growth in Innerwear with brands and products that appeal to younger consumers, drive consumer-centricity by delivering innovative products and improving awareness through investments in brand marketing and digital capabilities, and streamline its global portfolio.
In the fourth quarter of 2020, the Company began the implementation of its Full Potential plan and as part of its strategy to streamline its portfolio, the Company determined that its personal protective equipment (“PPE”) business was no longer a growth opportunity and recorded a charge of \$362,913 to write down its entire PPE inventory balance to its estimated net realizable value and a charge of \$26,400 to accrue for vendor commitments for PPE materials that were paid in 2021. Additionally, the Company commenced an initiative to reduce 20% of its SKUs in inventory in order to streamline product offerings while also implementing a formal lifecycle management process. As a result, the Company recorded a charge of \$192,704 to write down inventory to its estimated net realizable value taking into account these initiatives. These initiatives will position the Company for long-term growth by driving higher margin sales, lowering costs and improving service to customers.
In the first quarter of 2021, the Company announced that it reached the decision to exit its European Innerwear business as part of its strategy to streamline its portfolio under its Full Potential plan and determined that this business met held-for-sale and discontinued operations accounting criteria. Accordingly, the Company began to separately report the results of its European Innerwear business as discontinued operations in its Consolidated Statements of Income, and to present the related assets and liabilities as held for sale in the Consolidated Balance Sheets. On November 4, 2021, the Company announced that it reached an agreement to sell its European Innerwear business to an affiliate of Regent, L.P. and completed the sale on March 5, 2022. Unless otherwise noted, discussion within these notes to the consolidated financial statements relates to continuing operations. See Note “Assets and Liabilities Held for Sale” for additional information.
In addition, in the fourth quarter of 2021, the Company reached the decision to divest its U.S. Sheer Hosiery business, including the L’eggs brand, as part of its strategy to streamline its portfolio under its Full Potential plan and determined that this business met held-for-sale accounting criteria, The related assets and liabilities are presented as held for sale in the Consolidated Balance Sheets at December 31, 2022 and January 1, 2022. The operations of the U.S. Sheer Hosiery business are reported in “Other” for all periods presented in Note “Business Segment Information”. The Company is currently exploring potential purchasers for this business and expects to complete the sale within the next 12 months. See Note “Assets and Liabilities Held for Sale” for additional information.
HBI operations are managed and reported in three operating segments, each of which is a reportable segment for financial reporting purposes: Innerwear, Activewear and International. These segments are organized principally by product category and geographic location. Each segment has its own management team that is responsible for the operations of the segment’s businesses, but the segments share a common supply chain and media and marketing platforms.
The following table summarizes HBI operating segments by product category:
Segment | Primary Products | Primary Brands |
---|---|---|
Innerwear | Basics, including men’s underwear, women’s panties, children’s underwear and socks and intimate apparel, such as bras and shapewear | Hanes, Maidenform, Bali, Champion, Playtex, JMS/Just My Size, Bras N Things, Polo Ralph Lauren |
Activewear | T-shirts, fleece, sport shirts, performance T-shirts and shorts, sports bras, thermals and teamwear | Champion, Hanes, Gear for Sports, Comfortwash, Alternative, JMS/Just My Size, Hanes Beefy-T |
International | Activewear, men’s underwear, women’s panties, children’s underwear, intimate apparel, socks and home goods | Champion, Bonds, Sheridan, Bras N Things, Hanes, Wonderbra, Berlei, Playtex, Zorba, Sol y Oro, Rinbros, Polo Ralph Lauren |
Innerwear net sales decreased 11% compared to prior year primarily due to softer point-of-sale trends, impacts to replenishment orders from retailers’ decisions to reduce broader inventory positions, business disruption as a result of the ransomware attack in the second quarter of 2022 and the overlap of last year’s sales benefits from retailer restocking and government-stimulus spending partially offset by pricing actions taken and retail space gains in the first quarter of 2022.
Activewear net sales decreased 7% compared to prior year primarily due to softer point-of-sale trends primarily related to the Champion brand, retailer inventory levels and business disruption as a result of the ransomware attack in the second quarter of 2022. The net sales decrease was partially offset by growth in the collegiate and printwear channels and pricing actions primarily taken in the third quarter of 2022.
Net sales in the International segment decreased 7% compared to prior year due to unfavorable foreign currency exchange rates. The unfavorable impact of foreign currency exchange rates decreased net sales approximately \$182 million in 2022. International net sales on a constant currency basis, defined as net sales excluding the impact of foreign currency, increased 1%. The impact of foreign currency exchange rates is calculated by applying prior period exchange rates to the current year financial results.
Other net sales decreased primarily as a result of lower sales at our retail outlets during 2022 compared to prior year partially offset by increased sales from our supply chain to the European Innerwear business. HBI has continued certain sales from our supply chain to this business on a transitional basis after the sale in the first quarter of 2022. These sales and the related profit are included in Other in all periods presented and have not been eliminated as intercompany transactions in consolidation for the period when this business was owned by us.
HBI’s multi-year growth strategy (“Full Potential plan”) focuses on four pillars to drive growth and enhance long-term profitability and identifies the initiatives to unlock growth. HBI four pillars of growth are to grow the Champion brand globally, drive growth in Innerwear with brands and products that appeal to younger consumers, build e-commerce excellence across channels and streamline our global portfolio. In order to deliver this growth and create a more efficient and productive business model, HBI has launched a multi-year cost savings program intended to self-fund the investments necessary to achieve the Full Potential plan’s objectives. We remain confident that our strong brand portfolio, world-class supply chain and diverse category and geographic footprint will help us unlock our full potential, deliver long-term growth and create stockholder value.
Included in restructuring and other action-related charges within operating profit in 2022 and 2021 were \$60 million and\$132 million, respectively, of charges related to the implementation of our Full Potential plan. Full Potential plan charges in 2022 included charges related to supply chain segmentation of \$18 million to position our manufacturing network to align with revenue growth opportunities of our Full Potential plan demand trends, \$10 million related to corporate headcount reductions and a non-cash gain of\$4 million to adjust the valuation allowance related to the U.S. Sheer Hosiery business resulting from a decrease in carrying value due to changes in working capital. Full Potential plan charges in 2021 included a charge of \$16 million for an action to resize our U.S. corporate office workforce through a voluntary retirement program and impairment charges of \$7 million related to the full impairment of an indefinite-lived trademark related to a specific brand within the European Innerwear business that was excluded from the disposal group as it was not marketed for sale.
The Board of Directors has recently eliminated its prior dividend policy pursuant to which HBI has historically paid a cash dividend on our common stock on a quarterly basis in order to direct free cash flow toward reducing our debt. The declaration and payment of any dividend in the future will be subject to the approval of the Board of Directors and our dividend may thereafter be discontinued or reduced at any time. The Board of Directors regularly evaluates our capital allocation strategy and dividend policy, and any future determination to continue to pay dividends, and the amount of such dividends, will be at the discretion of the Board of Directors. The ability to pay cash dividends is also limited by restrictions or limitations on our ability to obtain sufficient funds through dividends from subsidiaries, as well as by contractual restrictions, including the requirements of the agreements governing our indebtedness. There can be no assurance that HBI will declare cash dividends in the future in any particular amounts, or at all.
OLD }——————- HanesBrands (NYSE: HBI) makes everyday apparel that is known and loved by consumers around the world for comfort, quality and value. Among the company’s iconic brands are Hanes, the leading basic apparel brand in the United States; Champion, an innovator at the intersection of lifestyle and athletic apparel; and Bonds, which is setting new standards for design and sustainability.
HBI employs 51,000 associates in 32 countries and has built a strong reputation for workplace quality and ethical business practices. In May 2021, HBI launched its Full Potential plan – the company’s roadmap to drive improved revenue and profits during the next three years and beyond.
Unlike most apparel companies, more than 70% of the apparel we sell is manufactured in our own facilities or those of dedicated contractors. Owning the majority of our supply chain not only impacts cost, scale and flexibility, but also the ability to adhere to best-in-class workplace and sustainability practices.
In 2021, HBI was one of two apparel manufacturers named one of the World’s Most Ethical Companies by Ethisphere and garnered a spot on Barron’s 100 Most Sustainable Companies for the third consecutive year. This follows the December 2020 announcement that HBI earned “A List” recognition for leadership in corporate sustainability in the CDP 2020 Climate Change Report.
We are committed to making the world a more comfortable, livable and inclusive place. We have established new, wide-ranging 2030 global sustainability goals and launched a new sustainability website, www.HBISustains.com, designed to increase our transparency on key metrics. We approach sustainability from a broad, holistic perspective and focus our efforts in areas addressed by the United Nations’ Sustainable Development Goals under three pillars: People, Planet and Product.
https://ir.hanesbrands.com/
https://finance.yahoo.com/quote/HBI
Previous Close 4.8800
Open 4.8000
Bid 4.4200 x 2900
Ask 4.4000 x 29200
Day's Range 4.3200 - 4.8500
52 Week Range 4.3200 - 13.2800
Volume 15,869,504
Avg. Volume 12,093,670
Market Cap 1.533B
Beta (5Y Monthly) N/A
PE Ratio (TTM) N/A
EPS (TTM) -0.3500
Earnings Date May 03, 2023
Forward Dividend & Yield N/A (N/A)
Ex-Dividend Date Nov 21, 2022
1y Target Est 4.64
Sector(s): Consumer Cyclical
Industry: Apparel Manufacturing
Full Time Employees: 50,000
Hanesbrands Inc., a consumer goods company, designs, manufactures, sources, and sells a range of basic apparel for men, women, and children. The company operates through three segments: Innerwear, Activewear, and International.
www.hanes.com/corporate
Bottom line up front
HBI fails some of the decision model checks. Revisit to see if buy or sell in June. Follow the link to the Conclusion.
Revision history
- 1/10/2022: Copied from VZ notebook and reorganized
- Feb 2022: updated quick look, reorganized flow of calculations, corrected usage of financial rates, organized end sections
- 23 Mar 2022: Cleaning up financial data spreadsheet. Removed NAIC tab. Removed duplicate reveneu data.
- 27 Mar 2022: MFG template copied from BMY
- 27 Jun 2023:
- Updates to narrative
- updated Market Cap and total value of common equity plot to look at last full year and current price history
- removed dividend payout analysis
- In the Financial ratios section, added return on capital to plot
- In the NAIC section, added profit margin to plot
- Added new section called Earnings yield
- Removed Percent earned on equity since it was another way of saying RoE
- Avg closing price calculated
Analysis
The following sections of this notebook contain the financial analysis for the company.
Todo:
update notebook with new organizationload other sheets to test with different dataadd red flag ratiosadd section to calculate future stock price, use number in IRRupdate spreadsheet with 2021 datafix Weighted After-Tax Yield in the print out of the DFC inputsFIX nopm and nopm_avg usageclean up commented codecheck one dollar premisefix outline levelsfix outline orderresearch preferred stock- check inputs to financial worksheets
check and fix links to yahoo financeverify shares outstandingcheck neg retained earningsadd fix it marksremove raw cellsreview Current newsreview most recent quarterly resultsread annual reportwrite analysis and commentarywrite conclusionsspell checkremove NAIC sheet and move data to mextrics sheet- save as MFG template before final cleanup and upload to github
- upload updated files to github
write blog report and post- review blog report to make more interesting
- why should I care about this company
- why the key features are important, what are key features
- add some “because of this…that” flow between and linking the key features
example note
\(\Large {\color {red} {\text {Note}}}\)
1) Stock screener results
This company was selected from the Fidelity stock screener results. The search results are based on Dividend yield (high and very high, 2.83% and higher), Volume 90 average (high and very high. 535k and higher) and Revenue Growth 5 years (0 or higher).
Current news
A review of receint SEC filings and financial news sites yahoo and google showed the following:
On May 24, 2022, the Company identified that it had become subject to a ransomware attack and activated its incident response and business continuity plans designed to contain the incident. As part of the Company’s forensic investigation and assessment of the impact, the Company determined that certain of its information technology systems were affected by the ransomware attack.
Upon discovering the incident, the Company took a series of measures to further safeguard the integrity of its information technology systems, including working with cybersecurity experts to contain the incident and implementing business continuity plans to restore and support continued operations. These measures also included resecuring data, remediation of the malware across infected machines, rebuilding critical systems, global password reset and enhanced security monitoring. The Company notified appropriate law enforcement authorities as well as certain data protection regulators, and in addition to the Company’s public announcements of the incident, the Company provided breach notifications and regulatory filings as required by applicable law starting in August 2022. At this time, the Company believes the incident has been contained, the Company has restored its critical information technology systems, and manufacturing, retail and other internal operations continue. There is no ongoing operational impact on the Company’s ability to provide its products and services. The Company maintains insurance, including coverage for cyber-attacks, subject to certain deductibles and policy limitations, in an amount that the Company believes appropriate.
The Company is named in two pending lawsuits in connection with its previously disclosed ransomware incident. On October 7, 2022, a putative class action was filed against “Hanes Brands Inc.” alleging, among other things, negligence, negligence per se, breach of implied contract, unjust enrichment, breach of implied covenant of good faith and fair dealing, unfair business practices under the California Business and Professions Code, and violations of the California Confidentiality of Medical Information Act in connection with the ransomware incident. The litigation is entitled, Roman v. Hanes Brands Inc., and is pending in the United States District Court for the Central District of California. Plaintiff Roman also subsequently filed a second putative class action with regard to the ransomware incident in the United States District Court for the Middle District of North Carolina on January 16, 2023, entitled Roman v. Hanesbrands Inc., which was voluntarily dismissed without prejudice on January 20, 2023. On October 13, 2022, another putative class action was filed against HanesBrands Inc. alleging, among other things, negligence, negligence per se, breach of implied contract, invasion of privacy, and unjust enrichment in connection with the ransomware incident. The litigation is entitled, Toussaint v. HanesBrands Inc. and is pending in the United States District Court for the Middle District of North Carolina. The pending lawsuits seek, among other things, monetary and injunctive relief. The Company is vigorously defending these matters and believes the cases are without merit. The Company does not expect any of these claims, individually or in the aggregate, to have a material adverse effect on its consolidated financial position or results of operations. However, at this early stage in the proceedings, the Company is not able to determine the probability of the outcome of these matters or a range of reasonably expected losses, if any. The Company maintains insurance, including coverage for cyber-attacks, subject to certain deductibles and policy limitations, in an amount that the Company believes appropriate.
During the year ended December 31, 2022, the Company incurred costs of \$15,427, net of expected insurance recoveries, related to the ransomware attack. The costs for the year ended December 31, 2022 included \$14,168 related primarily to supply chain disruptions, which are reflected in the “Cost of sales” line of the Consolidated Statements of Income and \$1,259, net of expected insurance recoveries, related primarily to legal, information technology and consulting fees, which are reflected in the “Selling, general and administrative expenses” line of the Consolidated Statements of Income. The Company continues to assess the security event and cannot determine, at this time, the full extent of the impact from such event on its business, results of operations or financial condition or whether such impact will ultimately have a material adverse effect.
Review quarterly results
Since this analysis mainly looks at the annual reports, a review of the quarterly reports and the most recent 12 months is needed to see if the recent quarterly trends match the yearly trends. - yahoo finance - The Compustat Company Research from Fidelity - SEC filings from Hanesbrands Inc. Investor Relations
Condensed Consolidated Statements of Income | 04/01/23 | 04/02/22 |
---|---|---|
Net sales | \$1,389,410 | \$1,576,156 |
Cost of sales | \$939,717 | \$991,978 |
Gross profit | \$449,693 | \$584,178 |
Selling, general and administrative expenses | \$392,374 | \$413,666 |
Operating profit | \$57,319 | \$170,512 |
Other expenses | \$14,771 | \$987 |
Interest expense, net | \$58,452 | \$31,963 |
Income (loss) from continuing operations before income tax expense | -\$15,904 | \$137,562 |
Income tax expense | \$18,500 | \$23,385 |
Income (loss) from continuing operations | -\$34,404 | \$114,177 |
(amounts in thousands) |
As is shown in the table above, HBI’s sales are down and they experienced a loss from continuing operations. Since I’m going to wait until later in the year to sell my shares, I can evaluate the second and third quarter results before making a final decision.
Average daily volume
Average daily volume: 5,510,768
Dividend yield
Forward dividend yield: 5.16% - no longer valid
\(\Large {\color {red} {\text {add review of compustat report}}}\)
Compustat Company Research Hanesbrands Inc NYSE: HBI Mar. 14, 2023
2) Load financial spreadsheet
Data from consolidated financial statements and annual reports was collected and entered into a spreadsheet. All numerical data is converted from thousands or millions of dollars to dollars. The stock share price history was obtained from yahoo and is included as a tab in the spreadsheet. Other tabs in the spreadsheet are various worksheets.
\(\Large {\color {red} {\text {need to organize folders on drive}}}\)
/home/jeff32/HPL_legacy_files/HPL_legacy_files/Documents/Dividend Investing/DCF data/HBI_Financials.xlsx
/home/jeff32/Documents/Dividend Investing/DCF data/HBI_Financials.xlsx
= 'HBI' # company ticker symbol
ticker #os.chdir('/home/jim/Documents/Dividend Investing/DCF data/')
'/home/jeff32/Documents/Dividend Investing/DCF data/')
os.chdir(
= ticker+'_Financials.xlsx'
file_name = pd.read_excel(file_name,sheet_name='DCF data')
df_dcf_sheet #df_NAIC_financials = pd.read_excel(file_name,sheet_name='NAIC data')
= pd.read_excel(file_name,sheet_name='metrics')
df_metrics_sheet = pd.read_excel(file_name,sheet_name='Historical Prices')
df_price_history
# change the working director back to the Jupyter folder
#os.chdir('/home/jim/Documents/JupyterLab/Discount Cash Flow Analysis/')
'/home/jeff32/Documents/JupyterLab/Discount Cash Flow Analysis/') os.chdir(
# convert dates from string to datetime format in stock price history
= []
price_date_list for i in range(len(df_price_history)):
str(df_price_history['Date'][i]), '%Y-%m-%d'))
price_date_list.append(datetime.strptime(
0, 'datetime', price_date_list) # insert a new column with datetime data
df_price_history.insert(=['datetime'], inplace=True) # sort data frame by datetime
df_price_history.sort_values(by
'datetime',inplace=True)
df_price_history.set_index(
#df_price_history.head()
2.1) Format data frame
Generate a new data frame that holds the financial data needed for the DCF model. Data from financial statements is copied into a spreadsheet which contains the data used in the analysis. The data in the DCF_data tab is in a consistent format for ease of use by this notebook. Standard names are used for the rows and columns.
#column names: fiscal years
= df_dcf_sheet.columns[1:].values.astype('datetime64[Y]')-1970
fy_data #line 0: Total revenue
= df_dcf_sheet.iloc[0].to_numpy()[1:].astype('float')
revenue_data #line 1: Cost of goods sold
= df_dcf_sheet.iloc[1].to_numpy()[1:].astype('float')
Cost_of_goods_sold_data #line 2: General and administrative
= df_dcf_sheet.iloc[2].to_numpy()[1:].astype('float')
General_and_administrative_data #line 3: Research and development
= df_dcf_sheet.iloc[3].to_numpy()[1:].astype('float')
Research_and_development_data #line 4: Depreciation and amortization
= df_dcf_sheet.iloc[4].to_numpy()[1:].astype('float')
Depreciation_and_amortization_data #line 5: Investment
= df_dcf_sheet.iloc[5].to_numpy()[1:].astype('float')
Investment_data # line 6: Income before income taxes
= df_dcf_sheet.iloc[6].to_numpy()[1:].astype('float')
Income_before_income_taxes_data # line 7: Income tax
= df_dcf_sheet.iloc[7].to_numpy()[1:].astype('float')
Income_tax_data # line 8: Accounts receivable
= df_dcf_sheet.iloc[8].to_numpy()[1:].astype('float')
Accounts_receivable_data # line 9: Inventories
= df_dcf_sheet.iloc[9].to_numpy()[1:].astype('float')
Inventories_data # line 10: Accounts payable
= df_dcf_sheet.iloc[10].to_numpy()[1:].astype('float')
Accounts_payable_data # line 11: Current assets
= df_dcf_sheet.iloc[11].to_numpy()[1:].astype('float')
Current_assets_data # line 12: Current liabilities
= df_dcf_sheet.iloc[12].to_numpy()[1:].astype('float')
Current_liabilities_data # line 13: Long term debt
= df_dcf_sheet.iloc[13].to_numpy()[1:].astype('float')
Long_term_debt_data # line 14: Shares outstanding
= df_dcf_sheet.iloc[14].to_numpy()[1:].astype('float') Shares_outstanding_data
# make a new data frame to store selected financial data
= pd.DataFrame(data={
df_dcf_data 'FY':fy_data[::-1],
'revenue':revenue_data[::-1],
'cost_of_goods_sold':Cost_of_goods_sold_data[::-1],
'general_and_administrative':General_and_administrative_data[::-1],
'research_and_development':Research_and_development_data[::-1],
'depreciation':Depreciation_and_amortization_data[::-1],
'investment':Investment_data[::-1],
'income_before_income_taxes':Income_before_income_taxes_data[::-1],
'income_tax':Income_tax_data[::-1],
'accounts_receivable':Accounts_receivable_data[::-1],
'inventories':Inventories_data[::-1],
'accounts_payable':Accounts_payable_data[::-1],
'current_assets':Current_assets_data[::-1],
'current_liabilities':Current_liabilities_data[::-1],
'long_term_debt':Long_term_debt_data[::-1],
'shares_outstanding':Shares_outstanding_data[::-1]
})
#df_dcf_data
3) Discounted cash flow analysis, baseline
Discounted cash flow (DCF) is a valuation method used to estimate the value of an investment based on its expected future cash flows. DCF analysis attempts to figure out the value of an investment today, based on projections of how much money it will generate in the future. In finance, discounted cash flow (DCF) analysis is a method of valuing a security, project, company, or asset using the concepts of the time value of money. The DCF method used in this notebook follows [1].
The value of any financial investment equals the present value of the expected future cash flows, discounted for risk and timing of these cash flows. The DCF method to value stocks is a four step process.
1. Develop a set of future free cash flows for the corporation based on revenue growth, net operating profit margin, income tax rate and fix and working capital requirements. 2. Estimate the discount rate for the cash flows based on expected timing and risk. 3. Discount the cash flows and total them to calculate the value for the corporation as a whole. 4. Subtract the debt, preferred stock value and other claims and divide by the number of shares outstanding to get the intrinsic value.
Sections - Revenue growth rate
- Net operating profit margin
- Tax rate
- Depreciation Rate
- Investment Rate
- Working Capital Rate
- Current Assets
- Current Liabilities
- Value of Debt Outstanding
- Current stock price
- Shares outstanding
- 10 year treasury bond yield
- Bond yield spread to treasury
- Preferred stock yield
- Equity risk premium
- Company specific beta
- DCF model inputs
- Future cash flows
Future forecast based on historical data
The DCF model uses historical financial data to estimate future cash flows. However, future changes are largely unpredictable, so we assume that the past record can be used as a rough guide to the future. The more questionable this assumption is, the less valuable is the analysis. So the DCF model is more useful when applied to stable well established companies, since companies with stable earnings are easier to forecast.
Revenue growth rate
The revenue growth rate (also sometimes called net sales) of the corporation plus any other revenues associated with the main operations of the business. It does not include dividends, interest income or non-operating income. Historic revenue data is obtained from consolidated income statements. The year over year change in revenue is calculated and converted to a percent, then an average revenue growth rate is calculated.
Adjustments for Hanesbrands Inc.
No adjustments for this company.
# calculate the percent change in revenue
= np.zeros(len(df_dcf_data['revenue'].to_numpy())) # percent change in revenue
pcr for i in range(len(df_dcf_data['revenue'].to_numpy()[0:-1])):
+1] = ((df_dcf_data['revenue'].to_numpy()[i+1] - df_dcf_data['revenue'].to_numpy()[i])/
pcr[i'revenue'].to_numpy()[i+1])*100
df_dcf_data[
= 100
width
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
= plt.subplots()
fig, ax1 'Revenue, $B')
ax1.set_ylabel(
# plot revenue as single bar
'FY'],df_dcf_data['revenue']/1e9, width,color='k')
plt.bar(df_dcf_data[
='y')
ax1.tick_params(axis
plt.grid()
# instantiate a second y-axes that shares the same x-axis
= ax1.twinx()
ax2 = 'tab:green'
color
'FY'],pcr,'+-g')
ax2.plot(df_dcf_data[
'% Change in revenue',color=color)
ax2.set_ylabel(='y', labelcolor=color)
ax2.tick_params(axis-10,15))
ax2.set_ylim((
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'Revenue')
plt.title( plt.show()
Observation:
Net sales decreased 8% during 2022 primarily due to the following: - Softer point-of-sale trends and higher retailer inventory levels as a result of the macroeconomic pressures; - The impact of the ransomware attack to the business; - Global supply chain disruptions resulting in product delays; - Ongoing COVID-related pressures on consumer traffic in certain markets in Asia; and - The unfavorable impact from foreign currency exchange rates in our International business of approximately \$182 million. - Partially offset by: Pricing actions taken throughout 2022.
Net Sales | for the year ending 12/31/2022 |
---|---|
Innerwear | \$2,429,966 |
Activewear | \$1,555,062 |
International | \$1,914,268 |
Other | \$334,354 |
Total | \$6,233,650 |
(amounts in thousands) |
HBI products are primarily distributed through HBI wholesale customers’ stores and websites, as well as through our own stores and websites. In 2022, approximately 69% of HBI total net sales were in the United States and approximately 31% were outside the United States. HBI largest customer is Walmart Inc. (“Walmart”), accounting for 16% of total net sales in 2022.
Sales to mass merchants in the United States accounted for approximately 19% of HBI total net sales in 2022 and included all of our product categories under our Hanes, Playtex, Maidenform and JMS/Just My Size brands, as well as licensed logo apparel. Mass merchants feature high-volume, low-cost sales of basic apparel items along with a diverse variety of consumer goods products, such as grocery and drug products and other hard lines. HBI largest mass merchant customer is Walmart.
A significant percentage of HBI total revenues (approximately 31% in 2022) is derived from markets outside the United States. HBI sells a majority of products in transactions denominated in U.S. dollars; however, HBI purchases many of their raw materials, pay a portion of wages and make other payments to participants in the supply chain in foreign currencies. As a result, when the U.S. dollar weakens against any of these currencies, HBI cost of sales could increase substantially.
Outside the United States, HBI may pay for materials or finished products in U.S. dollars, and in some cases a strengthening of the U.S. dollar could effectively increase HBI costs where they use foreign currency to purchase the U.S. dollars they need to make such payments.
Outlook for 2023 HBI 2023 guidance as follows: - Net sales of approximately \$6.05 billion to \$6.20 billion, net of approximately \$42 million of unfavorable foreign exchange impact;
- Operating profit of approximately \$446 million to \$496 million, net of approximately \$6 million of unfavorable foreign exchange impact;
- Restructuring and other action-related charges totaling \$60 million including Full Potential plan-related charges of approximately \$54 million included in operating profit and refinancing charges of \$6 million included in other expenses;
- Interest expense and other expenses of approximately \$306 million combined;
- Tax expense from continuing operations of approximately \$90 million to \$100 million;
- Diluted earnings per share from continuing operations of approximately \$0.14 to \$0.25;
- Cash flow from operating activities of approximately \$500 million; and
- Capital investments of approximately \$150 million, including capital expenditures of \$70 million within investing cash flow activities and cloud computing assets of \$80 million within operating cash flow activities.
Third-party brick-and-mortar wholesale revenue is primarily generated by sales of the Company’s products to retailers to support their brick-and-mortar operations. Also included within third-party brick-and-mortar wholesale revenue is royalty revenue from licensing agreements. The Company earns royalties through license agreements with manufacturers of other consumer products that incorporate certain of the Company’s brands. The Company accrues revenue earned under these contracts based upon reported sales from the licensees. Additionally, third-party brick-and-mortar wholesale revenue for the year ended January 2, 2021 includes \$518,309 of revenue from contracts with governments generated from the sale of both cloth face coverings and gowns for use to help mitigate the spread of the virus during the COVID-19 pandemic.
= pcr[-5:].mean()/100 # last five years
rgr_avg print('average revenue growth rate: {:.2f}%'.format(rgr_avg*100))
average revenue growth rate: -0.88%
Net operating profit margin
Net Operating Profit should reflect the future revenue generating ability and expense requirements of the operating business that comprise the ongoing operations of the company.
\(\text{NOPM} = \frac{\text{Revenue} - \text{Expenses}}{\text{Revenue}}\)
\(\text{Expenses} = \text{Cost of Goods Sold (CGS)} + \text{General and Administrative (G\&A)} + \text{Research and Development (R\&D)}\)
General and Administrative (G&A) is also called Sales, General and Administrative (SG&A)
Adjustments for Hanesbrands Inc.
No adjustments for this company.
# NOP = (Revenue - Expenses)
= (df_dcf_data['revenue'].to_numpy() - \
nop 'cost_of_goods_sold'].to_numpy() + \
(df_dcf_data['general_and_administrative'].to_numpy() + \
df_dcf_data['research_and_development'].to_numpy()) )
df_dcf_data[
# net operating profit margin as percent of revenue
= nop/df_dcf_data['revenue'].to_numpy()
nopm
# plot as four grouped bar chart with labels on right and working capital rate on left
# calculate position of bars
= []
x1_bar_position = []
x2_bar_position = []
x3_bar_position = []
x4_bar_position for i in df_dcf_data['FY']:
-relativedelta(months=3))
x1_bar_position.append(i-relativedelta(months=1))
x2_bar_position.append(i+relativedelta(months=1))
x3_bar_position.append(i+relativedelta(months=3))
x4_bar_position.append(i
= 40 # the width of the bars
width
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
= plt.subplots()
fig, ax1 'Net operating profit, \\$B')
ax1.set_ylabel(
'cost_of_goods_sold'].to_numpy()/1e9, width,label='CGS')
ax1.bar(x1_bar_position,df_dcf_data['general_and_administrative'].to_numpy()/1e9, width,label='G&A')
ax1.bar(x2_bar_position,df_dcf_data['research_and_development'].to_numpy()/1e9, width,label='R&D')
ax1.bar(x3_bar_position,df_dcf_data[/1e9, width,label='NOP')
ax1.bar(x4_bar_position,nop
='y')
ax1.tick_params(axis#ax1.set_ylim((0,4))
ax1.legend()
plt.grid()
# instantiate a second y-axes that shares the same x-axis
= ax1.twinx()
ax2 = 'tab:cyan'
color
'FY'],nopm*100,'+-c')
ax2.plot(df_dcf_data[
'% NOPM',color=color)
ax2.set_ylabel(='y', labelcolor=color)
ax2.tick_params(axis0,40))
ax2.set_ylim((
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'Net Operating Profit')
plt.title( plt.show()
Observation
The COVID-19 pandemic has impacted HBI business operations and financial results for 2020, as described in more detail under “Consolidated Results of Operations - Year Ended January 2, 2021 (“2020”) Compared with Year Ended December 28, 2019 (“2019”)” below, due to decreased customer traffic and temporary retail store closures worldwide. While most of our retail stores were temporarily closed for varying periods of time throughout 2020, most reopened by the end of the second quarter but have experienced, and are expected to continue to experience, reductions in customer traffic, and as a result, net sales. Sales of PPE, used to help mitigate the spread of the COVID-19 virus, partially offset the negative impact of the decline in net sales and earnings due to the COVID-19 pandemic on our financial results. Our e-commerce sites have remained open in all regions and online sales have grown as consumer spending continued to shift towards online shopping experiences due to the changing retail landscape as a result of the COVID-19 pandemic.
During the second quarter of 2020, HBI recorded \$11 million of bad debt charges for customer bankruptcies and \$20 million of charges to reserve for increased excess and obsolete inventory related primarily to canceled orders of seasonal inventory. Also during the second quarter of 2020, BHI completed a quantitative impairment analysis for certain indefinite-lived intangible assets as a result of the significant impact of the COVID-19 pandemic on their performance. Based on this analysis, HBI recorded impairment charges of \$20 million on certain indefinite-lived trademarks and other intangible assets within the European Innerwear business. In the third quarter of 2020, HBI recorded \$49 million of supply chain re-start up charges primarily related to incremental costs incurred, such as freight and sourcing premiums, to expedite product to meet customer demand following the extended shut-down of parts of our manufacturing network as a result of the COVID-19 pandemic. Additionally, in the fourth quarter of 2020, HBI recorded a \$25 million charge for the impairment of goodwill related to the U.S. Hosiery reporting unit primarily as a result of the significant impact that the COVID-19 pandemic has had on this business.
Operating profit as a percentage of net sales was 8.3% in 2022, representing a decrease from 11.7% in the prior year. Operating margin decreased as a result of lower sales volume, input cost inflation, impact from the ransomware attack, costs associated with our manufacturing time-out inventory reduction actions, deleverage from a higher proportion of transportation and distribution costs, unfavorable impact from foreign currency exchange rates and increased Full Potential plan-related investments in brand marketing and technology partially offset by pricing actions and cost reduction actions. Included in operating profit in 2022 and 2021 were charges of \$60 million and \$132 million, respectively, related to the implementation of the Full Potential plan.
Operating Activities Our overall liquidity has historically been driven by our cash flow provided by operating activities, which is dependent on net income and changes in our working capital. As compared to the prior year, higher net cash used by operating activities was due to changes in working capital primarily accounts payable, accruals, inventory due to inflationary increases, softer point-of-sale trends and supply chain disruptions, and increased capital investments in our cloud computing assets partially offset by improvement in accounts receivable and lower pension plan contributions in 2022. Net cash from operating activities includes a \$40 million contribution to our U.S. pension plan made in the first quarter of 2021.
- Advertising represents one of several brand building methods used by the Company. Advertising costs, which include the development and production of advertising materials and the communication of these materials through various forms of media, are expensed in the period the advertising first takes place. The Company recognized advertising expense in the “Selling, general and administrative expenses” line in the Consolidated Statements of Income of \$208,881, \$208,998 and \$113,586 in 2022, 2021 and 2020, respectively.
- Revenue received for shipping and handling costs is included in net sales and was \$13,578, \$19,461 and \$18,943 in 2022, 2021 and 2020, respectively. Shipping costs, which comprise payments to third-party shippers, and handling costs, which consist of warehousing costs in the Company’s various distribution facilities, were \$415,989, \$447,131 and \$389,252 in 2022, 2021 and 2020, respectively. The Company recognizes shipping, handling and distribution costs in the “Selling, general and administrative expenses” line in the Consolidated Statements of Income.
- Research and development costs are expensed as incurred and are included in the “Selling, general and administrative expenses” line in the Consolidated Statements of Income. Research and development includes expenditures for new product, technological improvements for existing products and process innovation, which primarily consist of salaries, consulting and supplies attributable to time spent on research and development activities. Additional costs include depreciation and maintenance for research and development equipment and facilities. Research and development expense was \$38,911, \$39,320 and \$37,367 in 2022, 2021 and 2020, respectively.
#Average net operating profit margin
= nopm[-5:].mean()
nopm_avg print('average net operating profit margin: {:.2f}%'.format(nopm_avg*100))
average net operating profit margin: 9.13%
Tax rate
Tax payments are taken from the consolidated income statement, provision for income taxes. The effect of taxes on profits is accounted for.
\(\text{Tax rate} = \frac{\text{Income taxes}}{\text{Income before income taxes}}\)
Adjustments for Hanesbrands Inc.
No adjustments for this company.
# plot as Grouped bar chart with labels on right and tax rate on left
# calculate position of bars
= []
x1_bar_position = []
x2_bar_position for i in df_dcf_data['FY']:
-relativedelta(months=1))
x1_bar_position.append(i+relativedelta(months=1))
x2_bar_position.append(i
# calculate tax rate
= df_dcf_data['income_tax']/df_dcf_data['income_before_income_taxes']
tax_rate
= 50 # the width of the bars
width
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
= plt.subplots()
fig, ax1 'dollars, \\$M')
ax1.set_ylabel(
= ax1.bar(x1_bar_position,df_dcf_data['income_before_income_taxes']/1e6, width,
rects1 ='Income before income taxes')
label= ax1.bar(x2_bar_position,df_dcf_data['income_tax']/1e6, width,
rects2 ='Income taxes')
label
='y')
ax1.tick_params(axis#ax1.set_ylim((-2e3,2e3))
ax1.legend()
plt.grid()
# instantiate a second y-axes that shares the same x-axis
= ax1.twinx()
ax2 = 'tab:green'
color
'FY'],tax_rate * 100,'+-g')
ax2.plot(df_dcf_data[
'% Tax rate',color=color)
ax2.set_ylabel(='y', labelcolor=color)
ax2.tick_params(axis0,100))
ax2.set_ylim((
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'Tax Rate')
plt.title( plt.show()
Observation:
HBI has a complex multinational tax structure with multiple types of intercompany transactions, and allocation of profits and losses among HBI and subsidiaries through intercompany transfer pricing agreements is subject to review by the Internal Revenue Service and other tax authorities.
The company’s tax payments and tax rate from 2016 to 2022 departed from the historically contestant average of about 12% as shown in the plot above. The 10K’s for the years 2017, 2020 and 2022 describe the changes to the tax law which caused the changes in these years. Additionally, the company has deferred taxes, tax credits and unrecognized tax benefits which complicate the analysis of the tax burden. The average tax rate calculated over the last five years is 47%, which as shown below results in a base line ISV of \$7. Adjusting the average tax rate to 20% would change the baseline ISV to \$10, which shows that the tax rate has a significant effect on the value of the company.
Taxes for 2017
- The 2017 enacted Tax Act significantly revised U.S. corporate income tax law by, among other things, reducing the corporate income tax rate to 21%, imposing a new minimum tax on global intangible low-taxed income (“GILTI”) and implementing a modified territorial tax system that includes a one-time transition tax on deemed repatriated earnings of foreign subsidiaries. Some of the tax provisions that become effective in the fiscal year 2018 are expected to increase HBI’s effective tax rates, such as the GILTI tax. Due to the complexities involved in accounting for the enactment of the Tax Act, SEC Staff Accounting Bulletin 118 (“SAB 118”) allows companies to record provisional estimates of the impacts of the Tax Act during a measurement period which is similar to the measurement period of up to one year from the enactment which is similar to the measurement period used when accounting for business combinations. The Company will continue to assess the impact of the recently enacted tax law on its consolidated financial statements.
- Income tax expense for 2017 includes a one-time provisional charge related to U.S. tax reform of \$457 million, primarily for the transition tax on deemed repatriated earnings of foreign subsidiaries and revaluation of our deferred tax assets and liabilities, to the lower corporate income tax rate of 21%.
- Income Tax Expense – income tax expense for 2017 includes a provisional charge related to the Tax Act of \$435 million, which includes a \$360 million transition tax charge on deemed repatriated earnings of foreign subsidiaries, a charge of \$72 million for the revaluation of our deferred tax assets and liabilities to the lower corporate income tax rate of 21% and a \$3 million charge related to the deductibility of employee compensation. In addition, HBI incurred incremental tax costs of approximately \$22 million for other impacts of tax reform and other actions taken in 2017. HBI’s effective income tax rate was 6.0% and 9.5% in 2016 and 2015, respectively. The lower effective income tax rate was primarily attributable to a lower proportion of earnings attributed to domestic subsidiaries, which are taxed at rates higher than foreign subsidiaries. Income tax expense also benefited from the adoption of accounting rules related to accounting for stock compensation, which required excess tax benefits and deficiencies to be recognized in income as they occur.
Taxes for 2020 (See 10K-2020 pdf pages 103 to 107)
- The Company generated income (loss) before income tax expense of \$(183,122), \$679,727, and \$643,581 for the years 2020, 2019, and 2018, respectively.
- In 2020, the Company continued to analyze the impacts of the Tax Act and recently issued regulations that have been published to help taxpayers interpret and apply the legislation. As a result of its analysis, Management changed its estimate of the tax liability due in connection with the one-time mandatory transition tax and recognized a \$38,315 income tax benefit in the current period.
Taxes for 2022
- As of December 31, 2022, the valuation allowance for deferred tax assets was \$626,540, made up of \$306,743 for foreign loss carry forwards, \$21,232 for other foreign deferred tax assets, \$63,619 for federal and state operating loss carry forwards, and \$234,946 for other federal and state deferred tax assets. The net change in the total valuation allowance for 2022 was \$320,319, which relates to an increase of \$24,172 for foreign loss carry forwards, an increase of \$9,166 for other foreign deferred tax assets, an increase of \$52,035 for federal and state operating loss carryforwards and an increase of \$234,946 for other federal and state deferred tax assets.
- During 2022, the Company recorded \$696,028 of additional foreign net operating losses due to tax-deductible impairments in Switzerland and Luxembourg. These losses are subject to recapture in Switzerland and Luxembourg such that they will be taxable in a future year, therefore deferred tax liabilities were recorded. The Company believes it is reasonably possible that the deferred tax liability in Switzerland will reverse within the next twelve months due to expected actions by the Company in 2023.
Income Tax Expense – The effective income tax rate was 137.2% and 10.3% for 2022 and 2021, respectively. The higher effective tax rate for 2022 was primarily due to non-cash discrete tax charges of \$423 million for valuation allowances established against U.S. deferred tax assets and tax impairments in Switzerland which generated deferred tax liabilities during 2022.
Current and deferred tax provisions (benefits) were:
Year ended December 31, 2022 | Current | Deferred | Total |
---|---|---|---|
Domestic | \$15,188 | \$201,112 | \$216,300 |
Foreign | \$83,607 | \$95,558 | \$179,165 |
State | -\$2,712 | \$91,154 | \$88,442 |
Total | \$96,083 | \$387,824 | \$483,907 |
(amounts in thousands) |
Deferred tax assets relate to temporary differences (differences between the assets and liabilities in the consolidated financial statements and the assets and liabilities in the calculation of taxable income) including net operating losses.
HBI continues to use a portfolio approach to release the income tax effects in accumulated other comprehensive loss related to pension and post retirement benefits. Under this approach, the income tax effects are released from accumulated other comprehensive loss based on the pre-tax adjustments to pension liabilities or assets recognized within other comprehensive income. Any tax effects remaining in accumulated other comprehensive loss are released only when the entire portfolio of the pension and post retirement benefits is liquidated, sold or extinguished.
In December 31, 2022, the Company had domestic tax credit carry forwards totaling \$10,859, which expire beginning after 2022.
In 2022, 2021, and 2020, the Company recognized reductions of unrecognized tax benefits for tax positions of prior years of \$311, \$12,599, and \$18,385, respectively. In 2022, 2021, and 2020, income tax benefits recognized in connection with the expiration of statutes of limitations were \$7,191, \$147, and \$16,655, respectively. The Company believes it is reasonably possible that the amount of unrecognized tax benefits may decrease by \$3,267 within the next 12 months due to expirations in statutes of limitations. (See pdf page 100 for table)
At December 31, 2022, the balance of the Company’s unrecognized tax benefits, which would, if recognized, affect the Company’s annual effective tax rate was \$28,444. The Company’s policy is to recognize interest and/or penalties related to income tax matters in income tax expense. The Company recognized \$81, \\(933 and \\\)(5,206) in 2022, 2021 and 2020, respectively, for interest and penalties classified as income tax expense (benefit) in the Consolidated Statements of Income. At December 31, 2022 and January 1, 2022, the Company had a total of \$6,303 and \$5,865, respectively, of interest and penalties accrued related to unrecognized tax benefits.
# Average tax rate
= tax_rate[-5:].mean()
tax_rate_avg print('average tax rate: {:.2f}%'.format(tax_rate_avg*100))
average tax rate: 46.81%
Depreciation Rate
The depreciation rate is used to project the future net investment cash flows. The effect is to reduce the amount of FCFF. Depreciation amounts are from the Consolidated Statement of Cash Flows, Depreciation and Amortization.
\(\text{Depreciation Rate}=\frac{\text{Depreciation and Amortization}}{\text{Revenues}}\)
Depreciation is the write off or expensing of a percentage of the historical cost of an asset over the asset’s useful life. Property, plant and equipment (PP&E) are long term or non current assets owned or controlled by the company and used to manufacture and or sell the company’s products. The balance sheet typically shows all categories of PP&E grouped together, net of accumulated depreciation. Depreciation represents wear and tear on an asset or the fact that an asset gets used up over time. Companies record depreciation expense in the income statement every year for all depreciable assets in service or used by the company during the year. The difference between GAAP and Tax Accounting methods is handled through deferred taxes.
Amortization is the write off or expensing of the cost of a financial instrument or an intangible asset over the shorter of its useful life or legal life. Amortization is similar to depreciation and reflects the declining useful life and value of the intangible asset over time. Companies in research and development intensive fields typically have many patents. Such industries include high technology, pharmaceuticals and chemicals.
# depreciation rate
= df_dcf_data['depreciation'] / df_dcf_data['revenue'].to_numpy()
depreciation_rate
# plot depreciation on left and rate on right
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
= plt.subplots()
fig, ax1 'dollars, $B')
ax1.set_ylabel(
'FY'],df_dcf_data['depreciation']/1e9, width=100,color='k')
ax1.bar(df_dcf_data[
='y')
ax1.tick_params(axis
plt.grid()
# instantiate a second y-axes that shares the same x-axis
= ax1.twinx()
ax2 = 'tab:Blue'
color
'FY'],depreciation_rate*100,'+-')
ax2.plot(df_dcf_data[
'% Depreciation rate',color=color)
ax2.set_ylabel(='y', labelcolor=color)
ax2.tick_params(axis#ax2.set_ylim((0,30))
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'Depreciation')
plt.title( plt.show()
Observation:
Average depreciation rate as as percentage of revenue over the last 5 years is 1.84%. The depreciation and amortization expense for 2022 is comprised of the following:
Depreciation and amortization expense: | 12/31/22 |
---|---|
Innerwear | \$26,518 |
Activewear | \$22,420 |
International | \$19,670 |
Other | \$3,341 |
Corporate | \$32,538 |
Total depreciation and amortization expense | \$106,267 |
(amounts in thousands) |
Property is stated at historical cost and depreciation expense is computed using the straight-line method over the estimated useful lives of the assets. Machinery and equipment is depreciated over periods ranging from one to 15 years and buildings and building improvements over periods of up to 40 years. A change in the depreciable life is treated as a change in accounting estimate and the accelerated depreciation is accounted for in the period of change and future periods. Additions and improvements that substantially extend the useful life of a particular asset and interest costs incurred during the construction period of major properties are capitalized. Repairs and maintenance costs are expensed as incurred. Upon sale or disposition of an asset, the cost and related accumulated depreciation are removed from the accounts.
# average depreciation rate
= depreciation_rate[-5:].mean()
depreciation_rate_avg print('average depreciation rate: {:.2f}%'.format(depreciation_rate_avg*100))
average depreciation rate: 1.84%
Investment Rate
Taken from Consolidated Statement of Cash Flows, Cash used for investing activities. Net investment in the dollar amount needed to support the growth of the firm. Included investments in properties, plant equipment in excess of the depreciation expenses associated with past investments. Net investment decreases the amount of money available to the stockholders. Investment in property, plant and equipment is necessary to both maintain service and sales and also to grow revenues and profits. Investment amounts should include capital expenditures and research and development.
\(Ir=\frac {\text {Capital Expenditures}}{\text{Revenues}}\)
For this company, the yearly investment amounts are taken from the Consolidated Statements of Cash Flows, Net Cash Used in Investing Activities.
Adjustments for Hanesbrands Inc.
No adjustments for this comapany.
# investment rate
= df_dcf_data['investment'] / df_dcf_data['revenue'].to_numpy()
investment_rate
# plot investment on left and rate on right
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
= plt.subplots()
fig, ax1 'dollars, \\$B')
ax1.set_ylabel(
'FY'],df_dcf_data['investment']/1e9, width=100,color='k')
ax1.bar(df_dcf_data[
='y')
ax1.tick_params(axis
plt.grid()
# instantiate a second y-axes that shares the same x-axis
= ax1.twinx()
ax2 = 'tab:Blue'
color
'FY'],investment_rate*100,'+-')
ax2.plot(df_dcf_data[
'% New Investment Rate',color=color)
ax2.set_ylabel(='y', labelcolor=color)
ax2.tick_params(axis#ax2.set_ylim((-10,40))
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'New Investment')
plt.title( plt.show()
Observation:
Average investment rate as as percentage of revenue over the last 5 years is 2.52%.
The investing activities shown in the 2022 K-10 are shown in the table below:
Investing activities | 12/31/22 |
---|---|
Capital expenditures | -\$112,122 |
Purchase of trademarks | -\$103,000 |
Proceeds from sales of assets | \$157 |
Other | -\$1,463 |
Net cash from investing activities | -\$216,428 |
(amounts in thousands) |
The following investments for the years 2013, 2016 and 2018 are described below.
- In October 2013, HBI expanded their portfolio of brands through the acquisition of Maidenform, a global intimate apparel company. Maidenform is a leading seller of bras, shapewear and panties under brands such as Maidenform , Flexees, Lilyette, Self Expressions and Sweet Nothings , as well as Donna Karan and DKNY intimate apparel under license. The acquisition was an all cash transaction valued at approximately \$581 million.
- HBI acquired Champion Europe on June 30, 2016. The acquisition, combined with Champion brand rights previously owned, unites the Champion brand globally and gives HBI a powerful platform for growth on every continent.
- HBI acquired Hanes Australasia on July 14, 2016.
- On July 14, 2016, the Company acquired 100% of the outstanding shares of Pacific Brands Limited (“Hanes Australasia”) for a total purchase price of AUD \$1,049,360 (US \$800,871).
- On February 12, 2018, HBI acquired 100% of the outstanding equity of BNT Holdco Pty Limited (“Bras N Things”) for a total purchase price of AUD \$498,236 (US \$391,572). The purchase price was subsequently revised to AUD \$495,224 (US \$389,205) due to a final working capital adjustment.
- In June of 2022, HBI purchased the Champion trademark for footwear in the United States, Puerto Rico and Canada from Keds, LLC (“KEDS”) for \$103 million.
# average investment rate
= investment_rate[-5:].mean()
investment_rate_avg print('average investment rate: {:.2f}%'.format(investment_rate_avg*100))
average investment rate: 2.52%
Working Capital Rate
Working capital is needed to support the corporate sales effort of any company. Often a company’s incremental change in net working capital either positive or negative is approximately proportional to its change in revenue.
\(\text{Working capital} = \text{Accounts Receivable} + \text{Inventories} - \text{Accounts Payable}\)
Working capital is a company’s net investment in its accounts receivable and its inventories (cash outflows), minus its accounts payable (a cash inflow). Working capital and taxes are cash outflows from the corporation that are not available to pay debts and stockholders.
Adjustments for Hanesbrands Inc.
No adjustments for this company.
# plot as four grouped bar chart with labels on right and working capital rate on left
# calculate position of bars
= []
x1_bar_position = []
x2_bar_position = []
x3_bar_position = []
x4_bar_position for i in df_dcf_data['FY']:
-relativedelta(months=3))
x1_bar_position.append(i-relativedelta(months=1))
x2_bar_position.append(i+relativedelta(months=1))
x3_bar_position.append(i+relativedelta(months=3))
x4_bar_position.append(i
# calculate working capital rate
= (df_dcf_data['accounts_receivable'] + df_dcf_data['inventories']) - \
working_capital 'accounts_payable']
df_dcf_data[= working_capital / df_dcf_data['revenue']
working_capital_rate
= 40 # the width of the bars
width
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
= plt.subplots()
fig, ax1 'dollars, \\$B')
ax1.set_ylabel(
= ax1.bar(x1_bar_position,df_dcf_data['accounts_receivable']/1e9, width,\
rects1 ='Accounts Receivable')
label= ax1.bar(x2_bar_position,df_dcf_data['inventories']/1e9, width, label='Inventory')
rects2
= ax1.bar(x3_bar_position,df_dcf_data['accounts_payable']/1e9, width, label='Accounts Payable')
rects2 = ax1.bar(x4_bar_position,working_capital/1e9, width, label='Working Capital')
rects2
='y')
ax1.tick_params(axis#ax1.set_ylim((-50,200))
ax1.legend()
plt.grid()
# instantiate a second y-axes that shares the same x-axis
= ax1.twinx()
ax2 = 'tab:Blue'
color
'FY'],working_capital_rate * 100,'+-')
ax2.plot(df_dcf_data[
'% Working Capital Rate',color=color)
ax2.set_ylabel(='y', labelcolor=color)
ax2.tick_params(axis0,50))
ax2.set_ylim((
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'Working Capital')
plt.title( plt.show()
Observation:
Average working capital rate as as percentage of revenue over the last 5 years is 24%.
Customers increasingly require some of products on an exclusive basis, which could cause an increase in the number of stock keeping units, or “SKUs,” that must carried and, consequently, increase inventory levels and working capital requirements
HBI’s overall liquidity has historically been driven by cash flow provided by operating activities, which is dependent on net income and changes in working capital. As compared to the prior year, higher net cash used by operating activities was due to changes in working capital primarily accounts payable, accruals, inventory due to inflationary increases, softer point-of-sale trends and supply chain disruptions, and increased capital investments in cloud computing assets partially offset by improvement in accounts receivable and lower pension plan contributions in 2022.
Accounts receivable consist primarily of amounts due from customers. HBI carries accounts receivable at their net realizable value. In determining the appropriate allowance for doubtful accounts, HBI evaluates receivables on a collection (pool) basis which are aggregated based on similar risk characteristics and consider a combination of factors, such as historical losses, the aging of trade receivables, industry trends, and our customers’ financial strength, credit standing and payment and default history. Changes in the characteristics of accounts receivables and the aforementioned factors, among others, are reviewed quarterly and may lead to adjustments in allowance for doubtful accounts. The calculation of the required allowance involves judgment by our management as to the impact of these and other factors on the ultimate realization of trade receivables. Charges to the allowance for doubtful accounts are reflected in the “Selling, general and administrative expenses” line and charges to the allowance for customer chargebacks and other customer deductions are primarily reflected as a reduction in the “Net sales” line in Consolidated Statements of Income.
Accounts receivable are stated at their net realizable value. The allowance for doubtful accounts reflects the Company’s best estimate of probable losses inherent in the accounts receivable portfolio. Trade receivables are evaluated on a collection (pool) basis and aggregated on the basis of similar risk characteristics which are determined on the basis of historical losses, the aging of trade receivables, industry trends, and its customers’ financial strength, credit standing and payment and default history.
The Company has entered into agreements to sell selected trade accounts receivable to financial institutions based on programs offered by certain of the Company’s largest customers as well as programs sponsored by the Company. As a result of the strong credit worthiness of these customers, the discount taken on most of these programs is less than the marginal borrowing rate on the Company’s variable rate credit facilities. In all agreements, after the sale, the Company does not retain any beneficial interests in the receivables. The applicable financial institution services and collects the accounts receivable directly from the customer for programs offered by the Company’s customers. For programs sponsored by the Company, the Company maintains continued involvement as the servicer to collect the accounts receivable from the customer and remit payment to the financial institution. Net proceeds of these accounts receivable sale programs are recognized in the Consolidated Statements of Cash Flows as part of operating cash flows. The Company recognized total funding fees of \$8,823, \$3,312 and \$4,932 in 2022, 2021 and 2020, respectively, for sales of accounts receivable to financial institutions in the “Other expenses” line in the Consolidated Statements of Income.
See ARS Facility on pdf page 91
HBI carries inventory on the balance sheet at the estimated lower of cost or market. Cost is determined by the first-in, first-out, or “FIFO,” method for our inventories. HBI carries obsolete, damaged and excess inventory at the net realizable value, which they determine by assessing historical recovery rates, current market conditions and our future marketing and sales plans.
Inventories are stated at the estimated lower of cost or net realizable value. Cost is determined by the first-in, first-out, or “FIFO”, method for inventories. Obsolete, damaged, and excess inventory is carried at the net realizable value, which is determined by assessing historical recovery rates, current market conditions and future marketing and sales plans. Rebates, discounts and other cash consideration received from a vendor related to inventory purchases are reflected as reductions in the cost of the related inventory item and are therefore reflected in cost of sales when the related inventory item is sold.
Inventories | 12/31/22 |
---|---|
Raw materials | \$69,279 |
Work in process | \$107,904 |
Finished goods | \$1,802,489 |
Total | \$1,979,672 |
(amounts in thousands) |
# average working capital rate
= working_capital_rate[-5:].mean()
working_capital_rate_avg print('average working capital rate: {:.2f}%'.format(working_capital_rate_avg*100))
average working capital rate: 24.19%
Current assets
Total Current Assets from the most recent balance sheet statement of the company. Current assets include inventory, cash and accounts receivables.
Adjustments for Hanesbrands Inc.
None for this company.
# plot Short Term Assets
= 100 # the width of the bars
width
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
'FY'],df_dcf_data['current_assets']/1e9, width)
plt.bar(df_dcf_data[
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'Current assets')
plt.title('dollars, \\$B')
plt.ylabel(
plt.grid() plt.show()
Observation:
The current assets for HBI are \$3.13B. Current assets are used to calculate the total corporate value.
= df_dcf_data['current_assets'].iloc[-1]
sta print('Current assets: ${:.2f}B'.format(sta/1e9))
Current assets: $3.13B
Current liabilities
Total Current Liabilities from the most recent balance sheet consolidated statement.
Adjustments for Hanesbrands Inc.
None for this company.
# plot Short Term Liabilities
= 100 # the width of the bars
width
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
'FY'],df_dcf_data['current_liabilities']/1e9, width)
plt.bar(df_dcf_data[
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'Current liabilities')
plt.title('dollars, \\$B')
plt.ylabel(
plt.grid() plt.show()
print('Average of current liabilities: ${:.2f}B'.format(df_dcf_data['current_liabilities'].mean()/1e9))
Average of current liabilities: $1.54B
Observation:
The current liabilities for HBI are \$1.79B. Current liabilities are used to calculate the total value of common equity.
= df_dcf_data['current_liabilities'].iloc[-1]
stl print('Current liabilities: ${:.2f}B'.format(stl/1e9))
Current liabilities: $1.79B
Value of Debt Outstanding
Amount of debt outstanding from the most recent balance sheet of the company.
Adjustments for Hanesbrands Inc.
None for this company.
# calculate the percent change in debt, pcd
= np.zeros(len(df_dcf_data['long_term_debt'].to_numpy())) # percent change in debt
pcd for i in range(len(df_dcf_data['long_term_debt'].to_numpy()[0:-1])):
+1] = ((df_dcf_data['long_term_debt'].to_numpy()[i+1] - df_dcf_data['long_term_debt'].to_numpy()[i])/
pcd[i'long_term_debt'].to_numpy()[i+1])*100
df_dcf_data[
= 100
width
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
= plt.subplots()
fig, ax1 'Dollars, $B')
ax1.set_ylabel(
# plot revenue as single bar
'FY'],df_dcf_data['long_term_debt']/1e9, width,color='k')
plt.bar(df_dcf_data[
='y')
ax1.tick_params(axis
plt.grid()
# instantiate a second y-axes that shares the same x-axis
= ax1.twinx()
ax2 = 'tab:green'
color
'FY'],pcd,'+-g')
ax2.plot(df_dcf_data[
'% Change in debt',color=color)
ax2.set_ylabel(='y', labelcolor=color)
ax2.tick_params(axis#ax2.set_ylim((-40,100))
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'debt')
plt.title( plt.show()
= pcd[1:].mean()/100
dgr_avg print('average debt growth rate: {:.2f}%'.format(dgr_avg*100))
average debt growth rate: 3.04%
Observation:
The total long term debt and other for HBI is \$3.61B. Currently the Debt to NOP ratio is 7. HBI Directors eliminated the quarterly cash dividend as they recently shifted their capital allocation strategy to pay down debt to bring leverage back to a range that is no greater than two to three times on a net debt-to-adjusted EBITDA basis. Future principal payments for all of the facilities described above are as follows: \$247,000 due in 2023, \$1,485,275 due in 2024, \$62,500 due in 2025, and \$2,077,500 due in 2026.
A summary of the Company’s debt is presented below:
Senior Secured Credit Facility | Interest Rate | Principal Amount | Maturity Date |
---|---|---|---|
Revolving Loan Facility | 5.83% | \$352,500 | 11/01/26 |
Term Loan A | 5.92% | \$975,000 | 11/01/26 |
4.875% Senior Notes | 4.88% | \$900,000 | 05/01/26 |
4.625% Senior Notes | 4.63% | \$900,000 | 05/01/24 |
3.5% Senior Notes | 3.50% | \$535,275 | 06/01/24 |
Accounts Receivable Securitization Facility | 5.09% | \$209,500 | 06/01/23 |
as of December 31, 2022 | (amounts in thousands) |
Total cash paid for interest related to debt in 2022, 2021 and 2020 was \$150,452, \$161,202 and \$157,094, respectively.
During 2022, 2021 and 2020, the Company paid \$3,159, \$8,346 and \$15,010, respectively, in capitalized debt issuance costs related to the Company’s financing arrangements within continuing operations. Debt issuance costs are amortized to interest expense over the respective lives of the debt instruments, which range from one to 10 years. As of December 31, 2022, the net carrying value of unamortized debt issuance costs for the revolving loan facilities, which is included in “Other noncurrent assets” in the Consolidated Balance Sheets, was \$6,831 and the net carrying value of unamortized debt issuance costs for the remainder of the Company’s debt, which is included in “Long-term debt” in the Consolidated Balance Sheets was \$13,198. The Company’s debt issuance cost amortization in continuing operations was \$7,300, \$12,305 and \$11,349 in 2022, 2021 and 2020, respectively.
= df_dcf_data['long_term_debt'].iloc[-1]
vod print('Total long term debt and other: ${:.2f}B'.format(vod/1e9))
Total long term debt and other: $3.61B
Current stock price
Most recent stock price for the company. The current stock price is used to calculate the market value of the firm. Use the market value when looking at market capitalization for common stock.
= 4.4 # current stock price
csp print('current stock price: ${:,.2f}'.format(csp))
current stock price: $4.40
The current stock price: \$4.40. The 52 week range is \$3.85 to \$12.13.
Dilution
Dilution occurs when a company issues new shares that result in a decrease in existing stockholders’ ownership percentage of that company. Stock dilution can also occur when holders of stock options, such as company employees, or holders of other optionable securities exercise their options. When the number of shares outstanding increases, each existing stockholder owns a smaller, or diluted, percentage of the company, making each share less valuable.
Investigate why there is a historic growth trend in number of shares outstanding. Search annual report for dilutive actions:
- share sales
- convertable debt
- employee options
Search results:
The Company established the Omnibus Incentive Plan to award stock options, stock appreciation rights, restricted stock, restricted stock units, deferred stock units, performance shares and cash to its employees, non-employee directors and employees of its subsidiaries to promote the interests of the Company, incent performance and retain employees. In April 2020, the stockholders of the Company approved the Hanesbrands Inc. 2020 Omnibus Incentive Plan (the “2020 Omnibus Plan”). The Company satisfies the requirement for common shares for share-based payments to employees pursuant to the 2020 Omnibus Plan by issuing newly authorized shares. The 2020 Omnibus Plan authorized a total of 11,000 shares of common stock of the Company for awards granted under the 2020 Omnibus Plan, plus the number of shares of common stock of the Company available for grant under the predecessor HanesbrandsInc. Omnibus Incentive Plan (the “Prior Plan”) that had not yet been made subject to awards under the Prior Plan as of the effective date of the 2020 Omnibus Plan. The 2020 Omnibus Plan authorized 74,220 shares for awards of stock options and restricted stock units, of which 14,033 shares were available for future grants as of December 31, 2022.
In addition, during 2020, the Company granted stock awards to two newly hired executive officers outside of the 2020 Omnibus Plan in reliance on the employment inducement exemption under the New York Stock Exchange’s Listed Company Manual Rule 303A.08.
There were no stock option exercises during 2022 or 2021. The total intrinsic value of options that were exercised during 2020 was \$3,299.
The total fair value of shares vested during 2022, 2021 and 2020 was \$13,199, \$25,201 and \$15,325, respectively.
At December 31, 2022, there was \$23,329 of total unrecognized compensation cost related to non-vested stock-based compensation arrangements, of which \$16,349, \$6,097, and \$883 is expected to be recognized in continuing operations in 2023, 2024, and 2025, respectively.
Certain of the international plans, specifically those acquired in connection with the purchase of Champion Europe, are in substance nonretirement postemployment benefit plans, which are future liabilities funded through future operational results of the Company. However, for purposes of consolidation, the Company is including these plans within the defined benefit reporting. At December 31, 2022 and January 1, 2022, the total amounts accrued for these plans were \$871 and \$1,171, respectively and the total expense was \$9, \$8 and \$16 for 2022, 2021 and 2020, respectively.
The potential dilution seems to be 85,224 shares (11,000 + 74,220) authorized under the Omnibus Incentive Plan. This represents 0.024% of the shares outstanding. At \$5 per share, this has a value of \$4.26M.
10 year treasury bond yield
The 10 year treasury yield is used as a measure of the risk free rate.
Yield: 3.45%
iShares 7-10 Year Treasury Bond ETF (IEF)
Average Yield to Maturity: 3.5%
= (3.45+3.5)/2/100 # 10 year treasury bond yield, average of data from sources listed above
tby print('10 year treasury bond yield: {:,.2f}%'.format(tby*100))
10 year treasury bond yield: 3.48%
Bond yield spread to treasury
The spread to treasury implies that all corporate debt will have a higher yield than yields associated with comparable maturity US Treasury Bonds. The best way to determine default risk is to see how a particular company’s debt is trading in the market and compare it on a spread basis with comparable maturity yields.
Look at the following or use a default rating systems that are published by the three major rating agencies, Standards and Poors Corp, Moody’s Investor Services and Fitch & Company.
PIMCO Active Bond Exchange-Traded Fund (BOND)
Yield: 3.44%
iShares 5-10 Year Investment Grade Corporate Bond ETF (IGIB)
Average Yield to Maturity: 5.15%
iShares 10+ Year Investment Grade Corporate Bond ETF (IGLB)
Average Yield to Maturity: 5.35%
Web resources: - http://www.standardpoor.com/
- http://bond.yahoo.com/rates.html
- http://www.moodys.com/cust/default.asp
- http://www.fitchibca.com/corporate/index.cfm
= ((3.44+5.15+5.35)/3-tby)/100 # bond yield spread (average) to treasury spread
bystt print('Bond yield spread to treasury: {:,.2f}%'.format(bystt*100))
Bond yield spread to treasury: 4.61%
Preferred stock yield
Amount of preferred stock outstanding from the most recent balance sheet of the company.
Adjustments for Hanesbrands Inc.
Preferred stock (50,000,000 authorized shares; \$.01 par value) Issued and outstanding — None
= 0/100 # preferred stock yield
psy print('preferred stock yield: {:,.2f}%'.format(psy*100))
= 0 # value of preferred stock
vps print('value of preferred stock: {:,.2f}'.format(vps))
preferred stock yield: 0.00%
value of preferred stock: 0.00
Company specific beta
The Beta used is Beta of Equity. Beta is the monthly price change of a particular company relative to the monthly price change of the S&P 500. The time period for Beta is 5 years when available. This value can be obtained at yahoo finance.
A measure of risk of an individual stock. It measures volatility of return - a higher beta means a higher risk. A financial model that uses Beta as its sole measure of risk (signal factor model) is called a Capital Asset Pricing Model (CAPM).
= 1.59 # company specific beta
beta print('Company specific beta: {:,.2f}'.format(beta))
Company specific beta: 1.59
DCF model inputs
Below are the DCF model inputs. These values were calculated above.
# various rates
= rgr_avg # revenue growth rate
rgr print('revenue growth rate: {:,.2f}%'.format(rgr*100))
= nopm_avg # net operating profit margin
nopm print('net operating profit margin: {:,.2f}%'.format(nopm*100))
= tax_rate_avg # tax rate
tr print('tax rate: {:,.2f}%'.format(tr*100))
= depreciation_rate_avg # depreciation rate (% of revenue)
dr print('depreciation rate: {:,.2f}%'.format(dr*100))
= investment_rate_avg # investment rate (% of revenue)
ir print('investment rate: {:,.2f}%'.format(ir*100))
= working_capital_rate_avg # working capital rate (% of revenue)
wcr print('working capital rate: {:,.2f}%'.format(wcr*100))
revenue growth rate: -0.88%
net operating profit margin: 9.13%
tax rate: 46.81%
depreciation rate: 1.84%
investment rate: 2.52%
working capital rate: 24.19%
Excess return period
The excess return period is based on a judgment call. The authors of [1] use the 1-5-7-10 rule. They group companies into one of four general categories and excess return periods. They use a 10 year excess return period to calculate what they would consider the maximum value. They use a more conservative 1 year, 5 year or 7 year return period to calculate a more reasonable or minimum value.
- 1 year: Boring companies that operate in a highly competitive, low margin industry in which they have nothing particular going for them.
- 5 year: Decent companies that have a recognizable name and decent reputation and perhaps a regulatory benefit (utility company), but can’t control pricing or growth.
- 7 year: Good companies with good brand names, large companies of scale, good marketing channels and consumer identification (e.g. McDonald’s)
- 10 year: Great companies with great growth potential, tremendous marketing power, band names and in-place benefits (e.g. Intel, Microsoft, Coca Cola, Disney)
The excess return period used for the base case is ten years, which should lead to a higher calculated intrinsic value.
# General Inputs
= df_dcf_data['FY'].iloc[-1].year # fiscal year to start excess return period
fy_start = 10 # excess return period, years
erp = df_dcf_data['revenue'].to_numpy()[-1] # starting revenues for excess return period
rev_start print('starting year: {:.0f}'.format(fy_start))
print('excess return period: {:.0f} years'.format(erp))
print('starting revenues: ${:,.2f}B'.format(rev_start/1e9))
print('shares outstanding: {:,.0f}'.format(so))
starting year: 2022
excess return period: 10 years
starting revenues: $6.23B
shares outstanding: 349,361,517
= vps # preferred stock, market value
ps_mv print('preferred stock, market value : ${:,.2f}B'.format(ps_mv/1e9))
= csp*so # common stock, market value
cs_mv print('common stock, market value: ${:,.2f}B'.format(cs_mv/1e9))
preferred stock, market value : $0.00B
common stock, market value: $1.54B
Long Term Debt, Market Value, ltd_mv
Use the book value for long term debt. Various online resources can be used to research this item. These include, Bondsonline and Bloomberg. The book value of debt and preferred stock is an accounting measure that relates to how much money was raised by the company when each security was issued. The market value of debt and the preferred and common stock is the price that specific obligations would trade at in today’s market.
Long term debt for firms can take one of two forms. It can be a long-term loan from a bank or other financial institution or it can be a long-term bond issued to financial markets, in which case the creditors are the investors in the bond. Firms often have long term obligations that are not captured in the long term debt item. These include obligations to lessors on assets that firms have leased, to employees in the form of pension fund and health care benefits yet to be paid, and to the government in the form of taxes deferred. In the last two decades, accountants have increasingly moved towards quantifying these liabilities and showing them as long term liabilities.
= vod # market value of long term debt
ltd_mv = ltd_mv+ps_mv+cs_mv # total market value
tmv print('total market value: ${:,.2f}B'.format(tmv/1e9))
total market value: $5.15B
Cost of Common Equity, cce
The expected excess return a hypothetical average investor would require of a diversified portfolio of stock (assumed beta = 1.0) over the yield on the 10-year Treasury Bond. The annual rate of return that an investor expects to earn when investing in shares of a company is known as the cost of common equity. It includes dividends and increases in the market value.
= tby+beta*eq_rp # cost of common equity or the expected return for the stock
cce print('cost of common equity: {:,.2f}%'.format(cce*100))
cost of common equity: 8.24%
Long Term Debt, Average Yield, ltd_ay
The total cost of long term debt.
= tby+bystt # long term debt average yield
ltd_ay print('long term debt average yield: {:,.2f}%'.format(ltd_ay*100))
long term debt average yield: 8.09%
Long Term Debt, After Tax Yield, ltd_aty
The tax benefits of long term debt. Interest payments are tax deductible for the company.
= ltd_ay*(1-tr) # long term debt after tax yield
ltd_aty print('long term debt after tax yield: {:,.2f}%'.format(ltd_aty*100))
= vod/tmv # weight for long term debt
ltd_pc = ltd_aty*ltd_pc # after tax effect of long term debt
ltd_ate = psy # preferred stock, average yield
ps_ay = ps_ay # preferred stock, average yield
ps_aty print('preferred stock, average yield: {:,.2f}%'.format(ps_aty*100))
= ps_mv/tmv # preferred stock, % capital
ps_pc = ps_aty*ps_pc # preferred stock, after tax effect
ps_ate = cce # common stock, average yield
cs_ay = cce # common stock, after tax yield
cs_aty print('common stock, after tax yield: {:,.2f}%'.format(cs_aty*100))
= cs_mv/tmv # common stock, % capital
cs_pc = cs_aty*cs_pc # common stock, after tax effect
cs_ate print('common stock, after tax effet: {:,.2f}%'.format(cs_ate*100))
= ltd_ate+ps_ate+cs_ate # total after tax effect
tate print('total after tax effect: {:,.2f}%'.format(tate*100))
= ltd_pc+ps_pc+cs_pc # total % Capital
tpc print('total % Capital: {:,.2f}%'.format(tpc*100))
long term debt after tax yield: 4.30%
preferred stock, average yield: 0.00%
common stock, after tax yield: 8.24%
common stock, after tax effet: 2.46%
total after tax effect: 5.48%
total % Capital: 100.00%
Weighted average cost of capital
A company’s weighted average cost of capital (WACC) is the weighted average of the company’s current cost of debt and equity calculated by using current debt, preferred stock and common stock market values. The WACC of the company, calculated after tax, is the discount rate used in the DCF valuation procedures. The WACC, which is the cost of the different components of financing used by the firm, weighted by their market value proportions. These include debt, preferred stock, and common stock.
WACC: Weighted Average Cost of Capital, the rate used to discount cash flows, based on the following three factors. 1. Base rate of return. 2. Expected return based on debt and preferred stock. 3. Expected return on common stock and Beta.
All adjusted for the tax advantage of interest payments and the percentage of debt, preferred stock and common stock.
= tate
wacc print('weighted average cost of capital: {:.1f}%'.format(wacc*100))
weighted average cost of capital: 5.5%
Future cash flows
The future cash flows to the firm are projected based on revenue growth. The cash flows are then discounted using the WACC and the ISV is calculated.
# make a list of the fiscal years in excess return period
= np.zeros(erp+1)
fy 0] = fy_start
fy[for i in range(1,erp+1):
=fy_start+i
fy[i]
= np.zeros(len(fy))
rev = np.zeros(len(fy))
ciwc 0] = rev_start #*rgr+rev_start # find the future revenue using constant revenue growth rate
rev[
for i in range(1,len(fy)):
= rev[i-1]*rgr+rev[i-1] # find the future revenue
rev[i] = (rev[i]-rev[i-1])*wcr # find the change in working capital
ciwc[i]
= np.zeros(len(fy)) # net operating profit
net_op = np.zeros(len(fy))
adj_taxes = np.zeros(len(fy))
nopat = np.zeros(len(fy))
invest = np.zeros(len(fy))
depre = np.zeros(len(fy))
net_invest = np.zeros(len(fy))
fcff = np.zeros(len(fy))
disc_fact = np.zeros(len(fy))
disc_fcff
# calculate values in table
for i in range(1,len(fy)):
= rev[i]*nopm # net operating profit margin
net_op[i] = net_op[i]*tr # net operating profit adjusted for taxes
adj_taxes[i] = net_op[i]-adj_taxes[i] # after tax net operating profit
nopat[i] = rev[i]*ir # future investments
invest[i] = rev[i]*dr # future depreciations
depre[i] = invest[i]-depre[i] # net investments
net_invest[i] = nopat[i]-net_invest[i]-ciwc[i] # free cash flow to the firm
fcff[i] = 1/((1+wacc)**i) # discount factor
disc_fact[i] = disc_fact[i]*fcff[i] # discounted free cash flow to the firm
disc_fcff[i]
= nopat[-1]/wacc*disc_fact[-1] # discounted corporate residual value
dcrv = disc_fcff.sum() # discounted excess return period FCFF
derp_fcff
= derp_fcff+dcrv+sta # total corporate value
tcv = tcv-vod-vps-stl # total value of common equity
tvce = tvce/so # intrinsic stock value
isv
# print cash flows in a table
print('{:4s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}'.format('Year','Rev','NOP','AdjTaxes',
'NOPAT','Invest.','Deprec.','dInvest.','dWC','FCFF','DF','DF*FCFF'))
for i in range(len(fy)):
print('{:4.0f}{:10,.0f}{:10,.0f}{:10,.0f}{:10,.0f}{:10,.0f}{:10,.0f}{:10,.0f}{:10,.0f}{:10,.0f}{:10,.4f}{:10,.0f}'.format(fy[i],
/1e6,net_op[i]/1e6,adj_taxes[i]/1e6,nopat[i]/1e6,invest[i]/1e6,depre[i]/1e6,(invest[i]-depre[i])/1e6,ciwc[i]/1e6,
rev[i]/1e6,disc_fact[i],disc_fcff[i]/1e6)) fcff[i]
Year Rev NOP AdjTaxes NOPAT Invest. Deprec. dInvest. dWC FCFF DF DF*FCFF
2022 6,234 0 0 0 0 0 0 0 0 0.0000 0
2023 6,179 564 264 300 156 114 42 -13 271 0.9481 257
2024 6,124 559 262 297 154 113 42 -13 269 0.8988 242
2025 6,070 554 259 295 153 112 41 -13 267 0.8521 227
2026 6,017 549 257 292 151 111 41 -13 264 0.8079 213
2027 5,964 544 255 290 150 110 41 -13 262 0.7659 201
2028 5,911 540 253 287 149 109 40 -13 260 0.7261 188
2029 5,859 535 250 284 147 108 40 -13 257 0.6884 177
2030 5,808 530 248 282 146 107 39 -12 255 0.6526 166
2031 5,756 525 246 280 145 106 39 -12 253 0.6187 156
2032 5,706 521 244 277 144 105 39 -12 251 0.5866 147
# Intrinsic Value
print('discounted excess return period FCFF: ${:,.2f}B'.format(derp_fcff/1e9))
print('discounted corporate residual value: ${:,.2f}B'.format(dcrv/1e9))
print('total corporate value: ${:,.2f}B'.format(tcv/1e9))
print('total value of common equity: ${:,.2f}B'.format(tvce/1e9))
= tvce # save value as baseline case
tvce_baseline = isv # save the isv for the baseline case
isv_baseline print('intrinsic stock value, baseline case: ${:,.2f}'.format(isv_baseline))
print('current stock price: ${:,.2f}'.format(csp))
discounted excess return period FCFF: $1.98B
discounted corporate residual value: $2.97B
total corporate value: $8.07B
total value of common equity: $2.67B
intrinsic stock value, baseline case: $7.64
current stock price: $4.40
Observation:
The base line DCF analysis produces an intrinsic stock value of \$7.64. An intrinsic value greater than the current price indicates that the stock is a potential value stock. Some adjustments will be made in the scenario 1 case.
List of all inputs to the DCF model
The following print statements format the inputs to the model similar to how they are presented on the Valuepro page.
print('{:>35s} {:<10.0f} {:>35s} {:,.3f}'.format('Excess return period, years:',erp,'Depreciation rate, %:',dr*100))
print('{:>35s} {:<10,.2f} {:>35s} {:,.3f}'.format('Starting revenues, $B:',
/1e9,'Investment rate, %:',ir*100))
rev_startprint('{:>35s} {:<10,.3f} {:>35s} {:,.3f}'.format('Revenue growth rate, %:',
*100,'Working capital rate, %:',wcr*100))
rgrprint('{:>35s} {:<10,.3f} {:>35s} {:,.3f}'.format('Net operating profit margin, %:',
*100,'Current assets, $B:',sta/1e9))
nopmprint('{:>35s} {:<10,.3f} {:>35s} {:.3f}'.format('Tax rate, %:',
*100,'Current liabilities, $B:',stl/1e9))
trprint('{:>35s} {:<10,.2f} {:>35s} {:,.2f}'.format('Current stock price, $:',
'Equity risk premium, %:',eq_rp*100))
csp,print('{:>35s} {:<10,.0f} {:>35s} {:,.2f}'.format('Shares outstanding, basic, M:',
/1e6,'Company specific beta:',beta))
soprint('{:>35s} {:<10,.2f} {:>35s} {:.3f}'.format('10 year treasury bond yield, %:',
*100,'Total long term debt and other, $B:',vod/1e9))
tbyprint('{:>35s} {:<10,.2f} {:>35s} {:,.3f}'.format('Bond yield spread to treasury, %:',
*100,'Value of preferred stock, $B:',vps/1e9))
bysttprint('{:>35s} {:<10,.2f}'.format('Preferred stock yield, %:',psy*100))
Excess return period, years: 10 Depreciation rate, %: 1.838
Starting revenues, $B: 6.23 Investment rate, %: 2.517
Revenue growth rate, %: -0.881 Working capital rate, %: 24.192
Net operating profit margin, %: 9.128 Current assets, $B: 3.132
Tax rate, %: 46.805 Current liabilities, $B: 1.791
Current stock price, $: 4.40 Equity risk premium, %: 3.00
Shares outstanding, basic, M: 349 Company specific beta: 1.59
10 year treasury bond yield, %: 3.48 Total long term debt and other, $B: 3.612
Bond yield spread to treasury, %: 4.61 Value of preferred stock, $B: 0.000
Preferred stock yield, %: 0.00
# weighted average cost of capital inputs
print('Weighted Average Cost of Capital')
print('Cost of common equity')
print('{:s}'.format('-'*37))
print('{:>32s} {:,.2f}'.format('10 year treasury bond yield, %:',tby*100))
print('{:>32s} {:,.2f}'.format('Company specific beta:',beta))
print('{:>32s} {:,.2f}'.format('Equity risk premium, %:',eq_rp*100))
print('{:s}'.format('-'*37))
print('{:>32s} {:,.2f}'.format('Cost of common equity, %:',cce*100))
print()
print('Market Capitalization and After-Tax Weighted Average Cost of Capital')
print()
print('{:s}{:^10s}{:^10s}{:^10s}{:^15s}{:^15s}'.format(' '*20,'Current','After-Tax','Market','%','Weighted After-'))
print('{:s}{:^10s}{:^10s}{:^10s}{:^15s}{:^15s}'.format(' '*20,'Yield','Yield','Value','Capitalization','Tax Yield'))
print('{:s}'.format('-'*80))
print('{:<15s}{:>12.2f}{:>10.2f}{:>10,.0f}{:>12.2f}{:>15.2f}'.format('Long term debt',
*100,(tby+eq_rp)*(1-tr)*100,vod/1e9,ltd_pc*100,ltd_ate*100))
ltd_ayprint('{:<15s}{:>12.2f}{:>10.2f}{:>10,.0f}{:>12.2f}{:>15.2f}'.format('Preferred stock',
*100,ps_ate*100,vps/1e9,ps_pc*100,ps_ate*100))
psyprint('{:<15s}{:>12.2f}{:>10.2f}{:>10,.0f}{:>12.2f}{:>15.2f}'.format('Common stock',
*100,cs_aty*100,cs_mv/1e9,cs_pc*100,cs_aty*100))
cs_ayprint('{:s}'.format('-'*80))
print('{:<37s}{:>10,.0f}{:>12.2f}{:>15.2f}'.format('',tmv/1e9,tpc*100,wacc*100))
Weighted Average Cost of Capital
Cost of common equity
-------------------------------------
10 year treasury bond yield, %: 3.48
Company specific beta: 1.59
Equity risk premium, %: 3.00
-------------------------------------
Cost of common equity, %: 8.24
Market Capitalization and After-Tax Weighted Average Cost of Capital
Current After-Tax Market % Weighted After-
Yield Yield Value Capitalization Tax Yield
--------------------------------------------------------------------------------
Long term debt 8.09 3.44 4 70.15 3.02
Preferred stock 0.00 0.00 0 0.00 0.00
Common stock 8.24 8.24 2 29.85 8.24
--------------------------------------------------------------------------------
5 100.00 5.48
4) DCF Scenarios
The following adjustments were made to various model parameters.
- excess return period was adjusted to a more conservative 5 years
- revenue growth rate was adjusted to 0% (base case = -0.881 %)
- net operating profit margin was adjusted to 9% (base case = 9.128%)
- tax rate was adjusted to 30% (base case = 46.805%)
- depreciation rate was adjusted to 2% (base case = 1.838%)
- investment rate was adjust to 2% (base case = 2.517%)
- working capital rate was set to an even 24% (base case = 24.192%)
- weighted average cost of capital was adjusted up by 2% to reflect higher interest rates and provide a margin of safety (base case = 5.59%)
print('adjusted DCF input values and rates')
= 5
erp print('excess return period: {:,.0f} years'.format(erp))
= 0/100
rgr print('revenue growth rate: {:,.1f}%'.format(rgr*100))
= isv_s1_nopm = 9/100 # save nopm rate for NAIC preferred method
nopm print('net operating profit margin: {:.2f}%'.format(nopm*100))
= isv_s1_tr = 30/100 # save tax rate for NAIC preferred method
tr print('tax rate: {:.2f}%'.format(tr*100))
= 2/100
dr print('depreciation rate: {:,.2f}%'.format(dr*100))
= 2/100 # investment rate (% of revenue)
ir print('investment rate: {:,.2f}%'.format(ir*100))
= 24/100
wcr print('working capital rate: {:,.1f}%'.format(wcr*100))
= (wacc+0.02) # weighted average cost of capital, increased by 2%
wacc print('weighted average cost of capital: {:.1f}%'.format(wacc*100))
adjusted DCF input values and rates
excess return period: 5 years
revenue growth rate: 0.0%
net operating profit margin: 9.00%
tax rate: 30.00%
depreciation rate: 2.00%
investment rate: 2.00%
working capital rate: 24.0%
weighted average cost of capital: 7.5%
# make a list of the fiscal years in excess return period
= np.zeros(erp+1)
fy 0] = fy_start
fy[for i in range(1,erp+1):
=fy_start+i
fy[i]
= np.zeros(len(fy))
rev = np.zeros(len(fy))
ciwc 0] = rev_start #*rgr+rev_start # find the future revenue using constant revenue growth rate
rev[
for i in range(1,len(fy)):
= rev[i-1]*rgr+rev[i-1] # find the future revenue
rev[i] = (rev[i]-rev[i-1])*wcr # find the change in working capital
ciwc[i]
= np.zeros(len(fy))
net_op = np.zeros(len(fy))
adj_taxes = np.zeros(len(fy))
nopat = np.zeros(len(fy))
invest = np.zeros(len(fy))
depre = np.zeros(len(fy))
net_invest = np.zeros(len(fy))
fcff = np.zeros(len(fy))
disc_fact = np.zeros(len(fy))
disc_fcff
# calculate values in table
for i in range(1,len(fy)):
= rev[i]*nopm # net operating profit
net_op[i] = net_op[i]*tr # net operating profit adjusted for taxes
adj_taxes[i] = net_op[i]-adj_taxes[i] # after tax net operating profit
nopat[i] = rev[i]*ir # future investments
invest[i] = rev[i]*dr # future depreciations
depre[i] = invest[i]-depre[i] # net investments
net_invest[i] = nopat[i]-net_invest[i]-ciwc[i] # free cash flow to the firm
fcff[i] = 1/((1+wacc)**i) # discount factor
disc_fact[i] = disc_fact[i]*fcff[i] # discounted free cash flow to the firm
disc_fcff[i]
= nopat[-1]/wacc*disc_fact[-1] # discounted corporate residual value
dcrv = disc_fcff.sum() # discounted excess return period FCFF
derp_fcff
= derp_fcff+dcrv+sta # total corporate value
tcv = tcv-vod-vps-stl # total value of common equity
tvce = tvce/so # intrinsic stock value
isv
# print cash flows in a table
print('{:4s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}'.format(
'Year','Rev','NOP','AdjTaxes',
'NOPAT','Invest.','Deprec.','dInvest.','dWC','FCFF','DF','DF*FCFF'))
for i in range(len(fy)):
print('{:4.0f}{:10,.0f}{:10,.0f}{:10,.0f}{:10,.0f}{:10,.0f}{:10,.0f}{:10,.0f}{:10,.0f}{:10,.0f}{:10,.4f}{:10,.0f}'.
format(fy[i],rev[i]/1e6,net_op[i]/1e6,adj_taxes[i]/1e6,nopat[i]/1e6,invest[i]/1e6,depre[i]/1e6,
-depre[i])/1e6,ciwc[i]/1e6,fcff[i]/1e6,disc_fact[i],disc_fcff[i]/1e6)) (invest[i]
Year Rev NOP AdjTaxes NOPAT Invest. Deprec. dInvest. dWC FCFF DF DF*FCFF
2022 6,234 0 0 0 0 0 0 0 0 0.0000 0
2023 6,234 561 168 393 125 125 0 0 393 0.9304 365
2024 6,234 561 168 393 125 125 0 0 393 0.8657 340
2025 6,234 561 168 393 125 125 0 0 393 0.8054 316
2026 6,234 561 168 393 125 125 0 0 393 0.7494 294
2027 6,234 561 168 393 125 125 0 0 393 0.6972 274
# Intrinsic Value
print('discounted excess return period FCFF: ${:,.2f}B'.format(derp_fcff/1e9))
print('discounted corporate residual value: ${:,.2f}B'.format(dcrv/1e9))
print('total corporate value: ${:,.2f}B'.format(tcv/1e9))
print('total value of common equity: ${:,.2f}B'.format(tvce/1e9))
= tvce # save value as scenario 1
tvce_S1 = isv # save the isv for scenario 1 case
isv_S1 print('intrinsic stock value, scenario 1 case: ${:,.2f}'.format(isv_S1))
print('current stock price: ${:,.2f}'.format(csp))
discounted excess return period FCFF: $1.59B
discounted corporate residual value: $3.66B
total corporate value: $8.38B
total value of common equity: $2.98B
intrinsic stock value, scenario 1 case: $8.53
current stock price: $4.40
The DCF model calculates with adjustments an intrinsic stock value of \$5.36, which is greater than the current stock price.
5) NACI stock selection guide analysis
This analysis follows the NAIC stock selection guide (SSG) [2]. The SSG relates revenue growth, EPS and share price history and makes a prediction about the future share price.
The National Association of Investors Clubs (NAIC) is a nonprofit organization dedicated to educating individual investors and investment clubs to become successful lifelong investors. NAIC’s Stock Selection Guide (SSG) is used in the following cells to analyze the company’s growth and whether the stock is selling at a reasonable price.
The SSG was originally developed in the 1950s as a paper worksheet by the not-for-profit National Association of Investors Corporation (NAIC). The SSG aims to aid individual investors in the fundamental analysis and selection of common stocks by reviewing components of a company’s growth, quality, and value.
Load data from metrics sheet
# column names: fiscal years
= df_metrics_sheet.columns[1:].values.astype('datetime64[Y]')-1970
fy_data # line 0: Net income
= df_metrics_sheet.iloc[0].to_numpy()[1:].astype('float')
net_income_data # line 1: Shareholder equity
= df_metrics_sheet.iloc[1].to_numpy()[1:].astype('float')
shareholder_equity_data # line 2: Total liabilities
= df_metrics_sheet.iloc[2].to_numpy()[1:].astype('float')
total_liabilities_data # line 3: Free cash flow, Net cash provided by operating activities
= df_metrics_sheet.iloc[3].to_numpy()[1:].astype('float')
free_cash_flow_data # line 4: Dividends
= df_metrics_sheet.iloc[4].to_numpy()[1:].astype('float')
dividends_data # line 5: Total assets
= df_metrics_sheet.iloc[5].to_numpy()[1:].astype('float')
total_assets_data # line 6: Earnings per share
= df_metrics_sheet.iloc[6].to_numpy()[1:].astype('float')
eps_data # line 7: Dividends per share
= df_metrics_sheet.iloc[7].to_numpy()[1:].astype('float')
dps_data # line 8: Total tangible assets
= df_metrics_sheet.iloc[8].to_numpy()[1:].astype('float')
total_tangible_assets_data # line 9: Liabilities w/o deposits
= df_metrics_sheet.iloc[9].to_numpy()[1:].astype('float')
liabilities_wo_deposits_data # line 10: Provision for credit losses
= df_metrics_sheet.iloc[10].to_numpy()[1:].astype('float')
provision_for_credit_losses_data # line 11: Short-term borrowings
= df_metrics_sheet.iloc[11].to_numpy()[1:].astype('float')
short_term_borrowings_data # line 12: Preferred stock
= df_metrics_sheet.iloc[12].to_numpy()[1:].astype('float')
preferred_stock_data # line 13: Net cash used in investing activities
= df_metrics_sheet.iloc[13].to_numpy()[1:].astype('float') net_cash_used_in_investing_activities_data
# make a new data frame to store data from metrics sheet
= pd.DataFrame(data={
df_metrics_data 'FY':fy_data[::-1],
'net_income':net_income_data[::-1],
'shareholder_equity':shareholder_equity_data[::-1],
'total_liabilities':total_liabilities_data[::-1],
'free_cash_flow':free_cash_flow_data[::-1],
'dividends':dividends_data[::-1],
'total_assets':total_assets_data[::-1],
'eps':eps_data[::-1],
'dps':dps_data[::-1],
'total_tangible_assets':total_tangible_assets_data[::-1],
'liabilities_wo_deposits':liabilities_wo_deposits_data[::-1],
'provision_for_credit_losses':provision_for_credit_losses_data[::-1],
'short_term_borrowings':short_term_borrowings_data[::-1],
'preferred_stock':preferred_stock_data[::-1],
'net_cash_used_in_investing_activities':net_cash_used_in_investing_activities_data[::-1]
})
#df_metrics_data
check for matching years in both data frames
if all(df_dcf_data['FY'] == df_metrics_data['FY']) != True:
print('error, years in data frame don\'t match')
# this is not python code, so jupyterlab will throw an error
stop else:
print('OK, years in data frame match')
OK, years in data frame match
NAIC section 1: Visual analysis
High and low price history for each year
From the daily price history obtained from yahoo finance, the high and low closing price for each is obtained and the data saved to the financial data frame as new columns.
\(\Large {\color {red} {\text {Avg closing price calculated, add to template}}}\)
#column names: fiscal years
= df_metrics_sheet.columns[1:].values.astype('str')[::-1]
years_list
# convert years to datetime format
= []
year_ended_list for i in years_list:
'%Y'))
year_ended_list.append(datetime.strptime(i,
# make empty lists to store open, close, average close, high and low price data for each fiscal year
= []
fy_open = []
fy_close = []
fy_avg_close = []
fy_high = []
fy_low
for i in year_ended_list:
= i
start = i + relativedelta(years=1)
end = df_price_history.truncate(before=start, after=end)
p1 if len(p1) == 0:
fy_open.append(np.nan)
fy_close.append(np.nan)
fy_avg_close.append(np.nan)
fy_high.append(np.nan)
fy_low.append(np.nan)else:
'Open'].iloc[0])
fy_open.append(p1['Close'].iloc[-1])
fy_close.append(p1['Close'].mean()) # could also use median
fy_avg_close.append(p1['Close'].max())
fy_high.append(p1['Close'].min())
fy_low.append(p1[
# convert from list to numpy array
= np.asarray(fy_open)
fy_open = np.asarray(fy_close)
fy_close = np.asarray(fy_avg_close)
fy_avg_close = np.asarray(fy_high)
fy_high = np.asarray(fy_low) fy_low
fy_close
array([ 6.35 , 5.465 , 8.955 , 17.567499, 27.905001, 29.43 ,
21.57 , 20.91 , 12.53 , 14.85 , 14.58 , 16.719999,
6.36 ])
fy_avg_close
array([ 6.53318452, 6.7058631 , 7.49818 , 13.47691467, 22.92302585,
30.99999004, 26.50714288, 22.03254979, 18.60091629, 16.0516666 ,
13.12505929, 18.31206347, 11.18338648])
Plotting the data
The annual sales, EPS and the high and low share price is plotted on a semilog plot. A consistent percentage change in the data will plot on the semi-log chart as a straight line.
The stock price is plotted separately from the sales and earnings for clarity.
fig, axs = plt.subplots(ncols=2, nrows=2, figsize=(5.5, 3.5),layout=“constrained”)
ax1 = plt.subplot(212) ax1.margins(0.05) # Default margin is 0.05, value 0 means fit ax1.plot(t1, f(t1))
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
# figsize() function to adjust the size
1,2,figsize=(15, 5)) # }--- put fix here
plt.subplots(
# using subplot function and creating
# plot one
1, 2, 1) # reseach this }------ generates warnings
plt.subplot(= 3 # the width of the bars
width #plt.bar(year_ended_list,fy_high-fy_low, width,bottom=fy_low,label='price')
= 0
j for i in year_ended_list:
= 'green'
color if fy_open[j] > fy_close[j]: color= 'red'
# high/low lines
=color, linewidth=width)
plt.plot([i,i],[fy_low[j],fy_high[j]],color# open marker
-relativedelta(months=1)], [fy_open[j],fy_open[j]], color=color, linewidth=width)
plt.plot([i,i# close marker
+relativedelta(months=1)], [fy_close[j],fy_close[j]], color=color, linewidth=width)
plt.plot([i,i+= 1
j
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
#plt.ylim((20,80))
'Yearly stock high and low price range')
plt.title('stock price, $')
plt.ylabel(#plt.legend()
plt.grid()
# using subplot function and creating plot two
1, 2, 2)
plt.subplot(
'FY'],df_dcf_data['revenue']/1e9,'+-',label='revenue, $B')
plt.plot(df_metrics_data['FY'],df_metrics_data['eps'],'+-',label='EPS, $')
plt.plot(df_metrics_data[
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
#plt.yscale('log')
#plt.yticks([0.1,1,10,100,1000,10000],['0.1','1','10','100','1000','10000'])
#plt.ylim((0.1,1000))
'Revenue and EPS')
plt.title('Revenue and EPS')
plt.ylabel(
plt.legend()
plt.grid()
# space between the plots
#plt.tight_layout(4) this line generates a warning
'''
/tmp/ipykernel_2327/525771534.py:10: MatplotlibDeprecationWarning: Auto-removal of overlapping axes is deprecated since 3.6 and will be removed two minor releases later; explicitly call ax.remove() as needed.
plt.subplot(1, 2, 1)
/tmp/ipykernel_2327/3890704171.py:10: MatplotlibDeprecationWarning: Auto-removal of overlapping axes is deprecated since 3.6 and will be removed two minor releases later; explicitly call ax.remove() as needed.
plt.subplot(1, 2, 1)
'''
# show plot
plt.show()
Observation:
The share price dramatically fell when the dividend was discontinued and has continued to decline as the EPS has fallen. The 52 week range is between \$3.85 and \$11.91. The pandemic and the current recession have impacted the business. It is interesting to note that the share price has trended down since 2015, while the revenue was increasing over the period from 2013 to 2019. In 2016 HBI took on additional debt to fund acquisitions.
\(\Large {\color {red} {\text {fix warning about axes}}}\)
NAIC section 3, Price earnings history
Section 3 of the SSG is the Price-Earnings history. The following table is built from the high and low prices each year and the earnings per share. The high and low Price/Earnings ratios are calculated for each year and are listed in the columns labeled h-per and l-per.
print('{:4s}{:>10s}{:>10s}{:>10s}{:>10s}{:>10s}'.format('year','high','low','eps',
'h-per','l-per'))
for i in range(len(year_ended_list)):
print('{:s}{:10,.2f}{:10,.2f}{:10,.2f}{:10,.2f}{:10,.2f}'.format(year_ended_list[i].strftime("%Y"),
'eps'][i],
fy_high[i], fy_low[i],df_metrics_data[/df_metrics_data['eps'][i],
fy_high[i]/df_metrics_data['eps'][i])) fy_low[i]
year high low eps h-per l-per
2010 7.70 5.42 0.55 14.07 9.89
2011 8.31 5.46 0.68 12.18 8.00
2012 9.12 5.55 0.42 21.86 13.29
2013 17.74 8.90 0.83 21.44 10.75
2014 28.93 16.04 1.00 28.79 15.96
2015 34.58 26.54 1.07 32.32 24.80
2016 31.18 21.53 1.41 22.11 15.27
2017 25.67 18.98 0.17 151.00 111.65
2018 23.24 11.62 1.48 15.70 7.85
2019 19.14 12.52 1.65 11.60 7.59
2020 17.62 7.17 -0.21 -83.90 -34.14
2021 22.37 14.40 0.22 101.68 65.45
2022 17.36 5.84 -0.36 -48.22 -16.22
Average high and P/E for select years
The average price to earning ratio based on high and low stock prices is calculated.
#Average high P/E for years
= (fy_high/df_metrics_data['eps']).mean()
pe_avg_high print('average high P/E {:.2f}'.format(pe_avg_high))
#Average low P/E for years
= (fy_low/df_metrics_data['eps']).mean()
pe_avg_low print('average low P/E {:.2f}'.format(pe_avg_low))
average high P/E 23.12
average low P/E 18.47
Estimate future EPS
A least squares fit is used to get the slope of the EPS data points.
= df_metrics_data['eps']
y = np.arange(len(y))
x = np.polyfit(x, y, 1)
m, c print('EPS slope: {:.2f}'.format(m))
print('EPS intercept: {:.2f}'.format(c))
= m*x + c # data points for each year lstsq_fit
EPS slope: -0.04
EPS intercept: 0.94
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
= plt.subplots()
fig, ax1 'EPS')
ax1.set_ylabel(
'FY'],df_metrics_data['eps'], 'o',label='EPS')
ax1.plot(df_metrics_data['FY'],lstsq_fit, '-',label='least squares fit')
ax1.plot(df_metrics_data[
='y')
ax1.tick_params(axis#ax1.set_ylim((0,4))
ax1.legend()
plt.grid()
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'EPS and least squares fit')
plt.title( plt.show()
Using the equation for the best fit line, find the y value for the eps point at five years in the future.
# estimated eps in 5 years
= m*(x[-1]+5) + c
eps_5yr_est print('estimated eps in 5 years: {:.1f}'.format(eps_5yr_est))
estimated eps in 5 years: 0.2
Using the high and low price to earning ratio from above and the projected eps, calculate the range of stock price in five years.
= eps_5yr_est*pe_avg_low
naic_price_eps_low = eps_5yr_est*pe_avg_high
naic_price_eps_high print('estimated price range in 5 years: ${:.2f} to ${:.2f}'.format(naic_price_eps_low,naic_price_eps_high))
estimated price range in 5 years: $4.01 to $5.02
This is the estimated price range of the stock based on projected EPS and is a guide for what the stock price might be if conditions remain the same. Since the slope of the EPS history is negative, the projected stock price is negative.
NAIC section 3: 5 year estimated EPS, preferred method
See page 87 and figure 10-1, Need the following data:
- estimate sales in 5 years based on sales growth
- NOPM
- Tax rate
- shares outstanding
Net Operating Profit should reflect the future revenue generating ability and expense requirements of the operating business that comprise the ongoing operations of the company.
\(\text{NOPM} = \frac{\text{Revenue} - \text{Expenses}}{\text{Revenue}}\)
Tax payments are taken from the consolidated income statement, provision for income taxes. The effect of taxes on profits is accounted for.
\(\text{Tax rate} = \frac{\text{Income taxes}}{\text{Income before income taxes}}\)
To get future EPS
\(\text{future EPS} = \frac {\text{future revenue} \times \text{NOPM} \times \text{(1-tax rate)}}{\text{number of shares}}\)
Revenue and least square fit
= df_dcf_data['revenue']/1e6
y = np.arange(len(y))
x = np.polyfit(x, y, 1)
m, c print('revenue slope: {:.2f}'.format(m))
print('revenue intercept: {:.2f}'.format(c))
= m*x + c # data points for each year lstsq_fit
revenue slope: 228.20
revenue intercept: 4411.07
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
= plt.subplots()
fig, ax1 'dollars, $M')
ax1.set_ylabel(
'FY'],df_dcf_data['revenue']/1e6, 'o',label='revenue')
ax1.plot(df_metrics_data['FY'],lstsq_fit, '-',label='least squares fit')
ax1.plot(df_metrics_data[
='y')
ax1.tick_params(axis#ax1.set_ylim((0,4))
ax1.legend()
plt.grid()
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'Revenue and least squares fit')
plt.title( plt.show()
Using the equation for the best fit line, find the y value for the EPS point at five years in the future.
# estimated revenue in 5 years
= m*(x[-1]+5) + c
rev_5yr_est print('estimated rev in 5 years: ${:,.1f}M'.format(rev_5yr_est))
estimated rev in 5 years: $8,290.5M
need to include estimate of number of shares outstanding in 5 years
print('starting revenues: ${:,.2f}'.format(rev_start/1e9))
starting revenues: $6.23
Using the adjusted NOPM and tax rate from scenario 1.
adjusted DCF input values and rates
= isv_s1_nopm # use nopm from scenario 1
pm_nopm = isv_s1_tr # use tr from scenario 1
pm_tax_rate
= rev_5yr_est*pm_nopm*(1-pm_tax_rate)*1e6/df_dcf_data['shares_outstanding'].iloc[-1]
pm_eps_5yr_est #pm_eps_5yr_est = rev_5yr_est*nopm_avg*1e6/df_dcf_data['shares_outstanding'].iloc[-1]
print('using preferred method: estimated eps in 5 years: ${:.2f}'.format(pm_eps_5yr_est))
using preferred method: estimated eps in 5 years: $1.50
Using the high and low price to earning ratio from above and the projected EPS, calculate the range of stock price in five years.
= pm_eps_5yr_est*pe_avg_low
naic_price_pm_low = pm_eps_5yr_est*pe_avg_high
naic_price_pm_high print('estimated price range in 5 years from preferred method: {:.2f} to {:.2f}'.format(
naic_price_pm_low,naic_price_pm_high))
estimated price range in 5 years from preferred method: 27.62 to 34.57
Observation: Based on revenue growth, the projected stock price is a bit higher than the current price. However, based on price history, the stock is not expected to appreciate.
6) Future stock price
The projected future stock price is estimated from the results shown in this notebook based on DCF intrinsic stock value, the NAIC method or a combination of both. The DCF method does not consider market sentiment or popularity of the stock, whereas the NAIC method looks at the PE and EPS to develop the historical consensus that the market has put on the price of the stock. Both the NAIC and the DCF valuation should be considered. The DCF valuation is of the current ISV which is used as an indication of the future value, since it is assumed that the market price will converge eventually to the intrinsic value.
The estimated future stock price considers the following:
- base case ISV
- Senario ISV
- NAIC EPS growth
- NAIC preferred method
Using 5 year NAIC as a conservative estimate for the 10 year value and the analysis results, a judgment call is made concerning the price to put on the future value of the stock.
print('estimated price range in 5 years from EPS: ${:.2f} to ${:.2f}'.format(naic_price_eps_low,naic_price_eps_high))
print('estimated price range in 5 years from preferred method: ${:.2f} to ${:.2f}'.format(
naic_price_pm_low,naic_price_pm_high))
print('intrinsic stock value, baseline case: ${:,.2f}'.format(isv_baseline))
print('intrinsic stock value, scenario 1 case: ${:,.2f}'.format(isv_S1))
print('current stock price: ${:,.2f}'.format(csp))
estimated price range in 5 years from EPS: $4.01 to $5.02
estimated price range in 5 years from preferred method: $27.62 to $34.57
intrinsic stock value, baseline case: $7.64
intrinsic stock value, scenario 1 case: $8.53
current stock price: $4.40
The estimated price range in 5 years from the preferred method is \$86.14 to \$116.85. Taking the average and using that value on the IRR calculations.
= (naic_price_pm_low+isv_S1)/2 # estimated future stock price
fsp print('estimated future stock price: ${:,.2f}'.format(fsp))
estimated future stock price: $18.07
7) Dividend payout
The dividend payout examines the amount shareholders are getting from the company relative to earnings or revenue. It is an important metric to determine how the business is operating and whether it has enough growth potential.
Dividend history
No dividends paid in 2010, 2011 and 2012. HBI Board of Directors eliminated the quarterly cash dividend as they recently shifted their capital allocation strategy to pay down debt to bring leverage back to a range that is no greater than two to three times on a net debt-to-adjusted EBITDA basis.
The code cells below have been set to raw since there is no dividend data and the yearly future cash flows are also set to zero.
calculate the percent change in dividends
pcd = np.zeros(len(df_metrics_data[‘dps’])) # percent change in dividend for i in range(len(df_metrics_data[‘dps’][0:-1])): pcd[i+1] = ((df_metrics_data[‘dps’][i+1] - df_metrics_data[‘dps’][i])/ df_metrics_data[‘dps’][i+1])*100
width = 100
Set the locator
locator = mdates.YearLocator() # every year fmt = mdates.DateFormatter(‘%Y’)
fig, ax1 = plt.subplots() ax1.set_ylabel(‘Dividend per share, $’)
plot revenue as single bar
plt.bar(df_metrics_data[‘FY’],df_metrics_data[‘dps’], width,color=‘k’)
ax1.tick_params(axis=‘y’) plt.grid()
Set the locator
locator = mdates.YearLocator() # every year fmt = mdates.DateFormatter(‘%Y’)
width = 50 # the width of the bars plt.bar(df_metrics_data[‘FY’],(df_metrics_data[‘dps’]/fy_high-df_metrics_data[‘dps’]/fy_low)100, width,bottom=df_metrics_data[‘dps’]/fy_low100,label=‘yield’) X = plt.gca().xaxis X.set_major_locator(locator) # Specify formatter X.set_major_formatter(fmt) plt.gcf().autofmt_xdate()
plt.ylim((1,12)) plt.title(‘Range of dividend yield each year’) plt.ylabel(‘dividend yield, %’) #plt.legend() plt.grid()
show plot
plt.show()
The dividend yield for the past five years has been in the 2.5 to 3.5 percent range.
Dividend payout ratio
The dividend payout ratio is a relative measure of how much the company is paying to shareholders in dividends compared to other metrics such as revenue, earnings or cash flow. The dividend payout ratio is plotted as a ratio of dividends to net income, free cash flow (Net cash provided by operating activities) and NOP. The payout ratio is useful for assessing a dividend’s sustainability. Companies are extremely reluctant to cut dividends since it can drive the stock price down and reflect poorly on management’s abilities.
Payout ratio using net income
Payout ratio using net income plots the ratio of dividend payout divided by net income:
\(\frac {\text{Dividends}}{\text{Net income}}\)
Depending on how net income is listed in the financial statements, it may include large other charges.
Payout ratio using cash flow
Payout ratio using net cash flow plots the ratio of dividend payout divided by cash flow:
\(\frac {\text{Dividends}}{\text{cash flow}}\)
Cash flow from operating activities usually includes a long list of items. Some insight might be obtained from this ratio. The trend should be consistent.
Payout ratio using NOP
Payout ratio using NOP plots the ratio of dividend payout divided by NOP:
\(\frac {\text{Dividends}}{\text{NOP}}\)
NOP is calculated above and might be different from net income listed in the financial statements. This ratio should be the lowest numerically of the three plots.
\(\Large {\color {red} {\text {not applicable anymore}}}\)
Set the locator
locator = mdates.YearLocator() # every year fmt = mdates.DateFormatter(‘%Y’)
fig, ax1 = plt.subplots() ax1.set_ylabel(‘Payout ratio’)
ax1.plot(df_metrics_data[‘FY’],df_metrics_data[‘dividends’]/df_metrics_data[‘net_income’], ‘-+’, label=‘Payout ratio using net income’) ax1.plot(df_metrics_data[‘FY’],df_metrics_data[‘dividends’]/df_metrics_data[‘free_cash_flow’], ’-*‘, label=’Payout ratio using cash flow’) ax1.plot(df_metrics_data[‘FY’],df_metrics_data[‘dividends’]/nop, ‘-+’, label=‘dividends/NOP’)
ax1.tick_params(axis=‘y’) #ax1.set_ylim((0,5)) ax1.legend() plt.grid()
X = plt.gca().xaxis X.set_major_locator(locator) # Specify formatter X.set_major_formatter(fmt) plt.gcf().autofmt_xdate()
plt.title(‘Payout ratio’) plt.show()
average the last three years
print(‘Dividends are paid at {:.1f}% of net income’.format( (df_metrics_data[‘dividends’]/df_metrics_data[‘net_income’])[-3:].mean()100)) print(‘Dividends are paid at {:.1f}% of cash flow’.format( (df_metrics_data[‘dividends’]/df_metrics_data[‘free_cash_flow’])[-3:].mean()100)) print(‘Dividends are paid at {:.1f}% of NOP’.format((df_metrics_data[‘dividends’]/nop)[-3:].mean()*100))
Payout ratio using net income: Net income includes large other charges and Amortization of acquired intangible assets. Large swings in ratio for net income indicates various charges against net income.
Payout ratio using cash flow: A ratio of greater than 1 for 2015. Currently below 33%.
Payout ratio using NOP: Follows ratio based on cash flow.
Dividend pay ratios for the last 3 years are near or below 50%.
Internal Rate of Return (IRR) calculations
The internal rate of return (IRR) is the discount rate that makes the net present value (NPV) of all cash flows equal to zero in a discounted cash flow analysis. Generally speaking, the higher an internal rate of return, the more desirable an investment is to undertake.
As explained above, the stock price fell when the dividend was elimated. The IRR calculations are based on average weighted cost plus the dividends actually received. The final stock price is based on ISV forecast.
The dividend growth rate has been set equal to zero.
= 0 # setting the average dividend growth rate to zero
adgr = np.zeros(len(df_metrics_data['dps'])) # future dividend payments
fdp 0] = df_metrics_data['dps'].iat[-1]
fdp[for i in range(len(df_metrics_data['dps'][0:-1])):
+1] = fdp[i]+fdp[i]*adgr/100 fdp[i
print('current stock price: ${:,.2f}'.format(csp))
print('my weighted average cost: ${:,.2f}'.format(11.37))
print('dividend payout received: ${:,.2f}'.format(df_metrics_data['dps'].iat[-1]))
#fsp = 100 #csp #500 #(csp + 102.05 + 138.82)/3 # final stock price, $
print('final stock price: ${:,.2f}'.format(fsp))
current stock price: $4.40
my weighted average cost: $11.37
dividend payout received: $0.60
final stock price: $18.07
#est_cf = np.copy(fdp) # make a copy of the estimated cash flow
= np.zeros(len(df_metrics_data['dps']))
est_cf
# cash flows, initial purchase, dividend payments and final sale
0] = est_cf[0] - 11.37 + df_metrics_data['dps'].iat[-1] #csp # subtract purchase price from the first dividend payment
est_cf[-1] = est_cf[-1] + fsp # include the sale price with the final dividend payment est_cf[
= np_financial.irr(est_cf) #np.irr(est_cf)
dividend_irr '''
this line generates an error
/tmp/ipykernel_2327/1130842036.py:1: DeprecationWarning: In accordance with NEP 32, the function irr was removed from NumPy version 1.20. A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
dividend_irr = np.irr(est_cf)
'''
print('IRR: {:.2f}%'.format(dividend_irr*100))
IRR: 4.41%
According to global investment bank Goldman Sachs, 10-year stock market returns have averaged 9.2% over the past 140 years. and according to 10-Year Annualized Rolling Returns, the long term average is about 10%. However there are many years where the rolling 10 year average return is below 4%.
The calculated IRR is 4.4%, which is lower than current interest rates.
8) Management performance
The following analysis somewhat follows the Warren Buffett strategy as outlined in [3]. This strategy is essentially value investing where companies are chosen that meet a set of criteria and who’s stock price is below the intrinsic value plus a margin of safety. These investments are usually held for the long term.
- Financial metrics
The following analysis looks at financial ratios over the evaluation period. Financial ratios can be used to judge management performance. Consistent favorable trends are an indication that management is taking care of the company.- Total liabilities to total assets ratio
- Debt to equity and debt to NOP ratios
- Financial ratios: RoE, RoA and PM
- NAIC section 2: Evaluating management
- Normalized data from consolidated statements
- Total liabilities to total assets ratio
- Market metrics
- One dollar premise
- Share price vs EPS
- Market capitalization
- One dollar premise
- Qualitative metrics
- Simple and understandable business model
- Favorable long term prospects
- Commodity reliance
- Consistent operating history
- rationality:
- focus on core aspects
- only invest in high ROE businesses
- focus on shareholder equity
- focus on core aspects
- Simple and understandable business model
Financial metrics
The following financial metrics are examined over the evaluation period. We are looking for favorable trends and evidence of consistent operations. Some red flags will also be evident in the plots.
Red flags:
- Shrinking gross profit margin
- Receivables growing faster than sales
- Rising debt-to-equity ratio
- Several years of revenue trending down
- Unsteady cash flow
- Rising accounts receivable or inventory in relation to sales
- Rising outstanding share count
- Consistently higher liabilities than assets
- Decreasing gross profit margin
- Increasing revenue while cash flow remains the same
- Unusual changes in key financial ratios
Total liabilities to total assets ratio
The ratio of liabilities to assets is plotted over the evaluation period. For most companies examined the liabilities are the total liabilities and the ratio is calculated using total assets and total tangible assets. Total tangible assets have goodwill and intangibles removed from the total. The ratio gives an indication of how much the company is worth versus how much the company owes. Ideally the ratio of liabilities to assets should be less than one.
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
= plt.subplots()
fig, ax1 'ratio')
ax1.set_ylabel(
# plot revenue as single bar
'FY'],df_metrics_data['total_liabilities']/df_metrics_data['total_assets'], '-+',
ax1.plot(df_metrics_data[='total liabilities to total assets')
label'FY'],df_metrics_data['total_liabilities']/df_metrics_data['total_tangible_assets'], '-*',
ax1.plot(df_metrics_data[='total liabilities to total tangible assets')
label
='y')
ax1.tick_params(axis=(1.8, 1))
ax1.legend(bbox_to_anchor
plt.grid()
# instantiate a second y-axes that shares the same x-axis
= ax1.twinx()
ax2 = 'tab:green'
color
#ax2.plot(year_ended_list,pcd,'+-g')
'FY'],
ax2.plot(df_metrics_data['total_assets']-df_metrics_data['total_tangible_assets'])/df_metrics_data['total_assets']*100,
(df_metrics_data[':',color=color,label='intangible assets to total assets')
'% intangible assets',color=color)
ax2.set_ylabel(='y', labelcolor=color)
ax2.tick_params(axis0,100))
ax2.set_ylim((=(1.7, 0))
ax2.legend(bbox_to_anchor
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'Total liabilities to total assets ratio')
plt.title( plt.show()
HBI has significant goodwill and intangible assets. As of January 2, 2021, HBI had approximately \$1.3 billion of goodwill and \$1.6 billion of trademarks and other identifiable intangibles on the balance sheet, which together represent 37% of the total assets. HBI does not amortize goodwill, but they assess for impairment at least annually and more often as triggering events occur. The timing of annual goodwill impairment testing is the first day of the third fiscal quarter.
Equity computed using tangible assets is negative. This would made debt to equity ratios shown below negative.
Debt to equity and debt to NOP ratios
The debt-to-equity ratio (D/E) is another key characteristic Buffett considers carefully. Buffett prefers to see a small amount of debt so that earnings growth is being generated from shareholders’ equity as opposed to borrowed money. The D/E ratio is calculated as follows:
\(\text{Debt-to-Equity Ratio} = \frac {\text{Total Liabilities}} {\text{Shareholders' Equity}} \text{ OR } \frac {\text{Long term debt}} {\text{Shareholders' Equity}}\)
This ratio shows the proportion of equity and debt the company uses to finance its assets, and the higher the ratio, the more debt—rather than equity—is financing the company. A high debt level compared to equity can result in volatile earnings and large interest expenses. For a more stringent test, investors sometimes use only long-term debt instead of total liabilities in the calculation above.
D/E is the traditional way to look at a company’s debt. Some rules of thumb say that the D/E should not be above 2 or 3. However the D/E company’s typically vary by industry. The ratio of LT debt to NOP gives the number of years it would take the company to pay back debt from NOP, the lower the number the shorter amount of time.
\(\text{Debt-to-NOP Ratio} = \frac {\text{Total Liabilities}} {\text{NOP}}\)
= df_metrics_data['total_tangible_assets'] - df_metrics_data['total_liabilities']
tangible_equity
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
= plt.subplots()
fig, ax1 'ratio')
ax1.set_ylabel(
'FY'],df_dcf_data['long_term_debt']/df_metrics_data['shareholder_equity'],
ax1.plot(df_metrics_data['-^',label='(LT debt)/Equity')
#ax1.plot(year_ended_list,df_dcf_data['long_term_debt']/tangible_equity, '-',label='(LT debt)/(Tangible Equity)')
'FY'],df_metrics_data['total_liabilities']/df_metrics_data['shareholder_equity'],
ax1.plot(df_metrics_data['-*',label='(total liabilities)/Equity')
#ax1.plot(year_ended_list,total_liabilities/BV, '-^',label='(total liabilities)/BV')
'FY'],df_metrics_data['total_liabilities']/nop, '-+',label='(total liabilities)/NOP')
ax1.plot(df_metrics_data[#ax1.plot(year_ended_list,total_liabilities/net_income, '-+',label='(total liabilities)/(net income)')
#ax1.plot(year_ended_list,df_dcf_data['current_liabilities']/nop, '-*',label='(current liabilities)/NOP')
#ax1.plot(year_ended_list,Liabilities_wo_deposits/nop, '-+',label='(Liabilities w/o deposits)/NOP')
='y')
ax1.tick_params(axis0,20))
ax1.set_ylim((#ax1.legend()
=(1.6, 1))
ax1.legend(bbox_to_anchor
plt.grid()
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'Various debt ratios')
plt.title( plt.show()
\(\Large {\color {red} {\text {fix plot, why the spike in 2020?}}}\)
Three debt ratios are plotted above. Prior to 2020 the debt ratios were somewhat consistent from year to year. In 2020 the NOP fell to almost zero and the total liabilities to NOP ratio when off the chart. From 2019 to the present the debt ratios have been rising and are now at concerning levels. It will be challenging for the HBI to reduce debt and grow revenues in the coming years.
—- OLD (LT debt)/Equity is plotted and is below 2 for each year in the evaluation period. A threshold of 2 is traditionally the upper limit for a reasonable amount of debt that a company should carry.
(total liabilities)/Equity is plotted and except for 2020 has been below the threshold of 2.
(total liabilities)/NOP to is plotted for each year in the evaluation period and except for 2019 is below 10. A value of 10 has been chosen as the threshold for this ratio and indicates how many years it would take the company to pay off total liabilities from the NOP generated each year. A threshold of ten seems like a reasonable level of debt measured against NOP.
Financial ratios (change)
Financial returns
Various ratios can be used to judge management performance. Consistent favorable trends are an indication that management is taking care of the company.
Return on equity
Sometimes return on equity (RoE) is referred to as stockholder’s return on investment. It reveals the rate at which shareholders earn income on their shares. Buffett always looks at RoE to see whether a company has consistently performed well compared to other companies in the same industry. RoE is calculated as follows:
\(\text{Return on Equity} = \frac {\text{Net Income}} {\text{Shareholder's Equity}}\)
Looking at the RoE in just the last year isn’t enough. The investor should view the RoE from the past five to 10 years to analyze historical performance.
\(\text{Shareholders’ Equity} = \text{Total Assets} − \text{Total Liabilities}\)
For this company, this method of getting Shareholders’ Equity gives negative values. On the Consolidated Balance Sheets, there is a line for Total stockholders’ equity, which is used.
Return on Assets
Return on assets is a profitability ratio that provides how much profit a company is able to generate from its assets. In other words, return on assets (RoA) measures how efficient a company’s management is in generating earnings from their economic resources or assets on their balance sheet.
\(\text{Return on assets} = \frac {\text{Net Income}} {\text{Tangible Assets}}\)
Calculating the RoA of a company can be helpful in comparing a company’s profitability over multiple quarters and years as well as comparing to similar companies. However, it’s important to compare companies of similar size and industry.
For example, banks tend to have a large number of total assets on their books in the form of loans, cash, and investments. A large bank could easily have over \$2 trillion in assets while putting up a net income that’s similar to companies in other industries. Although the bank’s net income or profit might be similar to an unrelated company and the bank might have high-quality assets, the bank’s RoA will be lower. The larger number of total assets must be divided into the net income, creating a lower RoA for the bank.
Similarly, auto manufacturing requires huge facilities and specialized equipment. A lucrative software company that sells downloadable programs online may generate the same net profits, but it could have a significantly higher RoA than its more asset-heavy counterparts. When utilizing this metric to compare productivity across businesses, it’s important to take into account what types of assets are required to function in a given industry, rather than simply comparing the figures.
Goodwill is a historical cost that does not have to be constantly replaced. Therefore, in most cases, return on tangible capital alone (excluding goodwill) will be a more accurate reflection of a business’s return on capital going forward. The ROE and ROA calculations used by many investment analysts are therefore often distorted by ignoring the difference between reported equity and assets and tangible equity and assets.
Profit Margin
A company’s profitability depends not only on having a good profit margin, but also on consistently increasing it. This margin is calculated by dividing net income by net sales. For a good indication of historical profit margins, investors should look back at least five years. A high-profit margin indicates the company is executing its business well, but increasing margins mean management has been extremely efficient and successful at controlling expenses.
\(\text{Profit Margin} = \frac {\text{Net Income}} {\text{Revenue}}\)
New Section
Return on Capital
The Return on Capital (RoC) is plotted to compare to RoA and RoE. RoC shows how much capital is needed to conduct the company’s business. RoC is the ratio of NOP to Working Capital, Tangible Assets and Depreciation. In addition to working capital requirements, a company must also fund the purchase of fixed assets necessary to conduct its business, such as real estate, plant, and equipment. The depreciated net cost of these fixed assets was then added to the working capital requirements to arrive at an estimate for tangible capital employed. Return on Capital (RoC) is calculated as follows:
\(\text{Return on Capital} = \frac {\text{NOP}} {\text{Working Capital + Tangible Assets + Depreciation}}\)
The RoC calculation uses NOP instead of net income to filter distortions due to taxes and debt.
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
= plt.subplots()
fig, ax1 'percent')
ax1.set_ylabel(
'FY'],df_metrics_data['net_income']/df_metrics_data['shareholder_equity']*100,
ax1.plot(df_metrics_data['-+',label='Return on Equity')
#ax1.plot(df_metrics_data['FY'],df_metrics_data['net_income']/df_metrics_data['total_assets']*100,
# '-*',label='Return on Assets')
'FY'],df_metrics_data['net_income']/df_metrics_data['total_tangible_assets']*100,
ax1.plot(df_metrics_data['-*',label='Return on Tangable Assets')
'FY'],nop/(working_capital+df_metrics_data['total_tangible_assets']+df_dcf_data['depreciation'])*100,
ax1.plot(df_metrics_data['-*',label='Return on Capital')
#ax1.plot(df_metrics_data['FY'],total_liabilities/shareholder_equity, '-^',label='D/E')
#ax1.plot(df_metrics_data['FY'],df_metrics_data['net_income']/df_dcf_data['revenue']*100,
# '-^',label='Profit margin')
='y')
ax1.tick_params(axis#ax1.set_ylim((0,14))
#ax1.legend()
=(1.05, 1))
ax1.legend(bbox_to_anchor
plt.grid()
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'Financial Returns')
plt.title( plt.show()
Set the locator
locator = mdates.YearLocator() # every year fmt = mdates.DateFormatter(‘%Y’)
fig, ax1 = plt.subplots() ax1.set_ylabel(‘percent’)
ax1.plot(df_metrics_data[‘FY’],df_metrics_data[‘net_income’]/df_metrics_data[‘shareholder_equity’]100, ‘-+’,label=‘Return on Equity’) ax1.plot(df_metrics_data[‘FY’],nop/df_metrics_data[‘shareholder_equity’]100, ‘-+’,label=‘Return on Equity w/ NOP’) #ax1.plot(df_metrics_data[‘FY’],df_metrics_data[‘net_income’]/df_metrics_data[‘total_assets’]100, # ’-’,label=‘Return on Assets’)
ax1.plot(df_metrics_data[‘FY’],df_metrics_data[‘net_income’]/df_metrics_data[‘total_tangible_assets’]100, ‘-’,label=’Return on Tangable Assets’) ax1.plot(df_metrics_data[’FY’],nop/df_metrics_data[’total_tangible_assets’]100,’-’,label=‘Return on Tangable Assets w/ NOP’)
ax1.plot(df_metrics_data[‘FY’],nop/(working_capital+df_metrics_data[‘total_tangible_assets’]+df_dcf_data[‘depreciation’])100, ’-’,label=‘Return on Capital’)
#ax1.plot(df_metrics_data[‘FY’],total_liabilities/shareholder_equity, ‘-^’,label=‘D/E’)
#ax1.plot(df_metrics_data[‘FY’],df_metrics_data[‘net_income’]/df_dcf_data[‘revenue’]*100, # ‘-^’,label=‘Profit margin’)
ax1.tick_params(axis=‘y’) #ax1.set_ylim((0,14)) #ax1.legend() ax1.legend(bbox_to_anchor=(1.05, 1)) plt.grid()
X = plt.gca().xaxis X.set_major_locator(locator) # Specify formatter X.set_major_formatter(fmt) plt.gcf().autofmt_xdate()
plt.title(‘Financial Returns’) plt.show()
Observation:
The trends for RoE, RoA (tangible) and RoC are shown above. RoE and RoA use net income in the equation show agree with results reported by analysts. RoC uses NOP instead of net income to eliminate the effects of taxes and debt. As shown in the plots, HBI is operating with negative RoE and RoA (tangible) in the current year. During the past few years the effects of the pandemic and global economic slowdown can be seen in the RoE and RoA (tangible) plots.
NAIC section 2: Evaluating management
This evaluating management section is patterned after the NAIC SSG report page 2; line A is percent pre-tax profit on sales and line B is percent earned on equity. The SSG section 2 looks to see if the trends are increasing or decreasing. In this report I’m going to look at the trends for profit margin and two measures of earnings yield.
Profit margin is a common measure of the degree to which a company or a particular business activity makes money. Expressed as a percentage, it represents the portion of a company’s sales revenue that it gets to keep as a profit, after subtracting all of its costs. The earnings yield refers to the earnings per share for for each 12-month period divided by the average price per share during the same period.
\(\text{Earning yield} = \frac {\text{EPS}} {\text{average closing price}}\)
If we use NOP in place of EPS and divide NOP by market capitalization (average share price multiplied by shares outstanding), we get another measure of earnings yield.
\(\text{Earning yield} = \frac {\text{NOP}} {(\text{shares outstanding} \times \text{average closing price}) + \text{long term debt}}\)
By using NOP, we can calculate the net operating profit yield on the full purchase price of a business.
\(\Large {\color {red} {\text {update this section, re-write}}}\)
See page 86, figure 9-1.
- % pretax profit on sales, (net before taxes)/rev - % earned on equity (another way of saying RoE, using calculated equity)
Percent earned on equity is a measure of financial performance calculated by dividing net income by equity. Because equity is equal to a company’s assets minus its debt, percent earned on equity is considered the return on net assets. Percent earned on equity is considered a gauge of a corporation’s profitability and how efficient it is in generating profits.
The following cells calculate the trends of the profit margin and earnings yield over the evaluation period and the most recent 5 years. The trend line is calculated using the numpy function, polyfit, which calculates the least squares polynomial fit with the degree of the fitting polynomial equal to 1.
= df_metrics_data['net_income']/df_dcf_data['revenue']
y = np.arange(len(y))
x = np.polyfit(x, y, 1)
m, c = m # save the slope of the least squared fit
pm_trend print('Profit margin slope: {:.2f}%'.format(m*100))
print('Profit margin intercept: {:.3f}'.format(c))
= m*x + c # data points for each year pm_lstsq_fit
Profit margin slope: -0.51%
Profit margin intercept: 0.078
= -6 # number of years to look back left_yr
= df_metrics_data['net_income'].iloc[left_yr:]/df_dcf_data['revenue'].iloc[left_yr:]
y = np.arange(len(y))
x = np.polyfit(x, y, 1)
m, c = m # save the slope of the least squared fit
pm1_trend print('Profit margin slope over the last {:.0f} years: {:.2f}%'.format(-left_yr,m*100))
print('Profit margin intercept point for the last {:.0f} years: {:.3f}'.format(-left_yr,c))
= m*x + c # data points for each year pm1_lstsq_fit
Profit margin slope over the last 6 years: -1.29%
Profit margin intercept point for the last 6 years: 0.058
The following cells calculate the earning yield based on EPS. The trend lines are also calculated.
= df_metrics_data['eps']/fy_avg_close
y = np.arange(len(y))
x = np.polyfit(x, y, 1)
m, c = m # save the slope of the least squared fit
y1_trend print('y1 slope: {:.2f}%'.format(m*100))
print('y1 intercept: {:.3f}'.format(c))
= m*x + c # data points for each year y1_lstsq_fit
y1 slope: -0.69%
y1 intercept: 0.087
= df_metrics_data['eps'].iloc[left_yr:]/fy_avg_close[left_yr:]
y = np.arange(len(y))
x = np.polyfit(x, y, 1)
m, c = m # save the slope of the least squared fit
y1a_trend print('y1 slope: {:.2f}%'.format(m*100))
print('y1 intercept: {:.3f}'.format(c))
= m*x + c # data points for each year y1a_lstsq_fit
y1 slope: -1.49%
y1 intercept: 0.063
The following cells calculate the earning yield based on NOP. The trend lines are also calculated.
= nop/(df_dcf_data['shares_outstanding']*fy_avg_close+df_dcf_data['long_term_debt'])
y = np.arange(len(y))
x = np.polyfit(x, y, 1)
m, c = m # save the slope of the least squared fit
y2_trend print('y2 slope: {:.2f}'.format(m*100))
print('y2 intercept: {:.3f}'.format(c))
= m*x + c # data points for each year y2_lstsq_fit
y2 slope: -0.28
y2 intercept: 0.088
= nop[left_yr:]/(df_dcf_data['shares_outstanding'].iloc[left_yr:]*fy_avg_close[left_yr:]+df_dcf_data['long_term_debt'].iloc[left_yr:])
y = np.arange(len(y))
x = np.polyfit(x, y, 1)
m, c = m # save the slope of the least squared fit
y2a_trend print('y2 slope: {:.2f}'.format(m*100))
print('y2 intercept: {:.3f}'.format(c))
= m*x + c # data points for each year y2a_lstsq_fit
y2 slope: -0.23
y2 intercept: 0.072
The following cell displays the profit margin and yield data along with trend lines.
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
= plt.subplots()
fig, ax1 'percent')
ax1.set_ylabel(#ax1.plot(year_ended_list,net_income, '-+',label='net income')
#ax1.plot(df_metrics_data['FY'],df_dcf_data['income_before_income_taxes']/df_dcf_data['revenue']*100, '-+',
# label='income before taxes/rev')
#ax1.plot(df_metrics_data['FY'],nop/df_dcf_data['revenue']*100, '-+',
# label='NOP/rev')
'FY'],df_metrics_data['net_income']/df_dcf_data['revenue']*100,
ax1.plot(df_metrics_data['-^k',label='net income/revenue')
'FY'],pm_lstsq_fit*100, '-.k')
ax1.plot(df_metrics_data[#ax1.plot(df_metrics_data['FY'],pm_lstsq_fit*100, '-k',label='pm least squares fit')
'FY'].iloc[left_yr:],pm1_lstsq_fit*100, '-k')
ax1.plot(df_metrics_data[
#ax1.plot(year_ended_list,df_dcf_data['revenue'], '-+',label='revenue')
#ax1.plot(year_ended_list,free_cash_flow, '-*',label='free cash flow')
'FY'],df_metrics_data['eps']/fy_avg_close*100,
ax1.plot(df_metrics_data['-+b',label='EPS/(avg closing price)')
#ax1.plot(df_metrics_data['FY'],y1_lstsq_fit*100, '-b',label='y1 least squares fit')
'FY'],y1_lstsq_fit*100, '-.b')
ax1.plot(df_metrics_data['FY'].iloc[left_yr:],y1a_lstsq_fit*100, '-b')
ax1.plot(df_metrics_data[
'FY'],nop/(df_dcf_data['shares_outstanding']*fy_avg_close+df_dcf_data['long_term_debt'])*100,
ax1.plot(df_metrics_data['-or',label='NOP/(so*avg closing price+long term debt)')
#ax1.plot(df_metrics_data['FY'],y2_lstsq_fit*100, '-r',label='y2 least squares fit')
'FY'],y2_lstsq_fit*100, '-.r')
ax1.plot(df_metrics_data['FY'].iloc[left_yr:],y2a_lstsq_fit*100, '-r')
ax1.plot(df_metrics_data[
='y')
ax1.tick_params(axis#ax1.set_ylim((0,18))
ax1.legend()
plt.grid()
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
'Profit margin & earnings yield')
plt.title( plt.show()
Observation:
Ideally the profit marging and yield trends should be growing or at least flat. In HBI’s case, the trends are negative.
Evaluating the treds.
\(\Large {\color {red} {\text {move these cells to section 9, decision model}}}\)
# check profit margin trends
if pm_trend < 0:
print('FAIL, profit margin trend over the evaluation period is negative at {:.1f}%'.format(pm_trend*100))
else:
print('PASS, profit margin trend over the evaluation period is positive at {:.1f}%'.format(pm_trend*100))
if pm1_trend < 0:
print('FAIL, profit margin trend over the last {:.0f} years is negative at {:.1f}%'.format(-left_yr,pm1_trend*100))
else:
print('PASS, profit margin trend over the last {:.0f} years is positive at {:.1f}%'.format(-left_yr,pm1_trend*100))
FAIL, profit margin trend over the evaluation period is negative at -0.5%
FAIL, profit margin trend over the last 6 years is negative at -1.3%
Checking trends based on EPS and NOP.
# check yield trend based on EPS
if pm_trend < 0:
print('FAIL, EPS yield trend over the evaluation period is negative at {:.1f}%'.format(y1_trend*100))
else:
print('PASS, EPS yield trend over the evaluation period is positive at {:.1f}%'.format(y1_trend*100))
if pm1_trend < 0:
print('FAIL, EPS yield trend over the last {:.0f} years is negative at {:.1f}%'.format(-left_yr,y1a_trend*100))
else:
print('PASS, EPS yield trend over the last {:.0f} years is positive at {:.1f}%'.format(-left_yr,y1a_trend*100))
FAIL, EPS yield trend over the evaluation period is negative at -0.7%
FAIL, EPS yield trend over the last 6 years is negative at -1.5%
# check yield trend based on NOP
if pm_trend < 0:
print('FAIL, NOP yield trend over the evaluation period is negative at {:.1f}%'.format(y2_trend*100))
else:
print('PASS, NOP yield trend over the evaluation period is positive at {:.1f}%'.format(y2_trend*100))
if pm1_trend < 0:
print('FAIL, NOP yield trend over the last {:.0f} years is negative at {:.1f}%'.format(-left_yr,y2a_trend*100))
else:
print('PASS, NOP yield trend over the last {:.0f} years is positive at {:.1f}%'.format(-left_yr,y2a_trend*100))
FAIL, NOP yield trend over the evaluation period is negative at -0.3%
FAIL, NOP yield trend over the last 6 years is negative at -0.2%
Set the locator
locator = mdates.YearLocator() # every year fmt = mdates.DateFormatter(‘%Y’)
fig, ax1 = plt.subplots() ax1.set_ylabel(‘percent’) #ax1.plot(year_ended_list,net_income, ‘-+’,label=‘net income’) ax1.plot(df_metrics_data[‘FY’],df_dcf_data[‘income_before_income_taxes’]/df_dcf_data[‘revenue’]100, ‘-+’, label=‘income before taxes/rev’) #ax1.plot(year_ended_list,df_dcf_data[‘revenue’], ‘-+’,label=‘revenue’) #ax1.plot(year_ended_list,free_cash_flow, ’-’,label=‘free cash flow’)
ax1.tick_params(axis=‘y’) #ax1.set_ylim((0,18)) #ax1.legend() plt.grid()
X = plt.gca().xaxis X.set_major_locator(locator) # Specify formatter X.set_major_formatter(fmt) plt.gcf().autofmt_xdate()
plt.title(‘% pretax profit on sales’) plt.show()
\(\Large {\color {red} {\text {New section, also add to template}}}\)
Earnings yield
describe: - EPS/(avg closing price) - NOP/(so*avg closing price)
need to calculate the avg price in the period
fy_avg_price = (fy_high+fy_low)/2 fy_avg_price
Set the locator
locator = mdates.YearLocator() # every year fmt = mdates.DateFormatter(‘%Y’)
fig, ax1 = plt.subplots() ax1.set_ylabel(‘percent’)
ax1.plot(df_metrics_data[‘FY’],df_metrics_data[‘eps’]/fy_avg_close*100, ‘-+’,label=‘EPS/(avg closing price)’)
ax1.plot(df_metrics_data[‘FY’],nop/(df_dcf_data[‘shares_outstanding’]fy_avg_close)100, ‘-+’,label=’NOP/(so*avg closing price)’)
’’’ ax1.plot(df_metrics_data[‘FY’],df_metrics_data[‘net_income’]/df_metrics_data[‘total_assets’]100, ‘-’,label=’RoA’) ax1.plot(df_metrics_data[’FY’],nop/(working_capital+df_metrics_data[’total_tangible_assets’])100,’-’,label=‘RoC’)
ax1.plot(df_metrics_data[‘FY’],df_metrics_data[‘net_income’]/df_metrics_data[‘shareholder_equity’]100, ‘-+’,label=‘RoE’) ax1.plot(df_metrics_data[‘FY’],df_metrics_data[‘net_income’]/df_metrics_data[‘total_assets’]100, ‘-’,label=’RoA’) ax1.plot(df_metrics_data[’FY’],df_metrics_data[’net_income’]/df_dcf_data[’revenue’]100,’-^‘,label=’Profit margin’) ’’’
ax1.tick_params(axis=‘y’) #ax1.set_ylim((0,14)) #ax1.legend() ax1.legend(bbox_to_anchor=(1.05, 1)) plt.grid()
X = plt.gca().xaxis X.set_major_locator(locator) # Specify formatter X.set_major_formatter(fmt) plt.gcf().autofmt_xdate()
plt.title(‘Earnings yield’) plt.show()
Set the locator
locator = mdates.YearLocator() # every year fmt = mdates.DateFormatter(‘%Y’)
fig, ax1 = plt.subplots() ax1.set_ylabel(‘percent’)
#ax1.plot(year_ended_list,shareholder_equity/df_dcf_data[‘revenue’]100, ‘-+k’, # label=‘shareholder equity/rev’) #ax1.plot(year_ended_list,net_income/shareholder_equity100, ‘-+’,label=‘RoE’) ax1.plot(df_metrics_data[‘FY’], df_metrics_data[‘net_income’]/(df_metrics_data[‘total_assets’]-df_metrics_data[‘total_liabilities’])*100, ‘-+’,label=‘RoE’)
ax1.tick_params(axis=‘y’) #ax1.set_ylim((0,12)) #ax1.legend() plt.grid()
X = plt.gca().xaxis X.set_major_locator(locator) # Specify formatter X.set_major_formatter(fmt) plt.gcf().autofmt_xdate()
plt.title(‘% earned on equity’) plt.show()
Percent earned on equity (another way of saying RoE). Percent earned on equity trend has been flat up to 2015, then became erratic.
Percent earned on equity is a measure of financial performance calculated by dividing net income by equity. Because equity is equal to a company’s assets minus its debt, percent earned on equity is considered the return on net assets. Percent earned on equity is considered a gauge of a corporation’s profitability and how efficient it is in generating profits.
Set the locator
locator = mdates.YearLocator() # every year fmt = mdates.DateFormatter(‘%Y’)
fig, ax1 = plt.subplots() ax1.set_ylabel(‘percent’)
ax1.plot(df_metrics_data[‘FY’],df_metrics_data[‘net_income’]/df_metrics_data[‘total_assets’]100, ‘-’,label=’RoA’) ax1.plot(df_metrics_data[’FY’],nop/(working_capital+df_metrics_data[’total_tangible_assets’])100,’-’,label=‘RoC’) ax1.plot(df_metrics_data[‘FY’],nop/(df_dcf_data[‘shares_outstanding’]fy_avg_close)100, ‘-+’,label=‘earnings yield’)
’’’ ax1.plot(df_metrics_data[‘FY’],df_metrics_data[‘net_income’]/df_metrics_data[‘shareholder_equity’]100, ‘-+’,label=‘RoE’) ax1.plot(df_metrics_data[‘FY’],df_metrics_data[‘net_income’]/df_metrics_data[‘total_assets’]100, ‘-’,label=’RoA’) ax1.plot(df_metrics_data[’FY’],df_metrics_data[’net_income’]/df_dcf_data[’revenue’]100,’-^‘,label=’Profit margin’) ’’’
ax1.tick_params(axis=‘y’) #ax1.set_ylim((0,14)) #ax1.legend() ax1.legend(bbox_to_anchor=(1.05, 1)) plt.grid()
X = plt.gca().xaxis X.set_major_locator(locator) # Specify formatter X.set_major_formatter(fmt) plt.gcf().autofmt_xdate()
plt.title(‘RoA and RoC’) plt.show()
Plot normalized data from consolidated statements
The following charts examine data from the consolidated financial statements and compare normalized trends over the evaluation period. The first chart plots normalized revenue along with normalized EPS, NOP and free cash flow. All values are normalized to the starting value in the series. Change relative to the normalized starting value can be seen over the evaluation period. Ideally the normalized parameters plotted should track revenue. Any large departures indicate an area of concern.
Normalized consolidated statement of income
The following chart shows normalized revenue plotted with normalized parameters from the consolidated statement of income.
\(\Large {\color {red} {\text {look at BMI and update normalized plots}}}\)
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
# set look back range, left_yr is the index into the date range
= -10
left_yr
'FY'][left_yr:],
plt.plot(df_metrics_data['revenue'][left_yr:]-df_dcf_data['revenue'].iloc[left_yr])/np.abs(df_dcf_data['revenue'].iloc[left_yr])*100,
(df_dcf_data['^-',label='Revenue')
'FY'][left_yr:],
plt.plot(df_metrics_data['eps'][left_yr:]-df_metrics_data['eps'].iloc[left_yr])/np.abs(df_metrics_data['eps'].iloc[left_yr])*100,
(df_metrics_data['-.',label='EPS')
'FY'][left_yr:],
plt.plot(df_metrics_data[-nop[left_yr])/np.abs(nop[left_yr])*100,
(nop[left_yr:]'-.',label='NOP')
'FY'][left_yr:],
plt.plot(df_metrics_data['free_cash_flow'][left_yr:]-df_metrics_data['free_cash_flow'].iloc[left_yr])/np.abs(df_metrics_data['free_cash_flow'].iloc[left_yr])*100,
(df_metrics_data['-.',label='Free cash flow')
# net income
'FY'][left_yr:],
plt.plot(df_metrics_data['net_income'][left_yr:]-df_metrics_data['net_income'].iloc[left_yr])/np.abs(df_metrics_data['net_income'].iloc[left_yr])*100,
(df_metrics_data['-.',label='Net income')
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()# Changes x-axis range
-1])
plt.gca().set_xbound(year_ended_list[left_yr], year_ended_list[
#plt.ylim((-100,500))
'Normalized income statement data')
plt.title('percent change')
plt.ylabel(#plt.legend()
=(1.6, 1))
plt.legend(bbox_to_anchor
plt.grid()
# space between the plots
#plt.tight_layout(4)
# show plot
plt.show()
Observation
It’s concerning that free cash flow and EPS do not trend with revenue.
Normalized income statement 5 year look back
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
# set look back range, left_yr is the index into the date range
= -6
left_yr
'FY'][left_yr:],
plt.plot(df_metrics_data['revenue'][left_yr:]-df_dcf_data['revenue'].iloc[left_yr])/np.abs(df_dcf_data['revenue'].iloc[left_yr])*100,
(df_dcf_data['^-',label='Revenue')
'FY'][left_yr:],
plt.plot(df_metrics_data['eps'][left_yr:]-df_metrics_data['eps'].iloc[left_yr])/np.abs(df_metrics_data['eps'].iloc[left_yr])*100,
(df_metrics_data['-.',label='EPS')
'FY'][left_yr:],
plt.plot(df_metrics_data[-nop[left_yr])/np.abs(nop[left_yr])*100,
(nop[left_yr:]'-.',label='NOP')
'FY'][left_yr:],
plt.plot(df_metrics_data['free_cash_flow'][left_yr:]-df_metrics_data['free_cash_flow'].iloc[left_yr])/np.abs(df_metrics_data['free_cash_flow'].iloc[left_yr])*100,
(df_metrics_data['-.',label='Free cash flow')
# net income
'FY'][left_yr:],
plt.plot(df_metrics_data['net_income'][left_yr:]-df_metrics_data['net_income'].iloc[left_yr])/np.abs(df_metrics_data['net_income'].iloc[left_yr])*100,
(df_metrics_data['-.',label='Net income')
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()# Changes x-axis range
-1])
plt.gca().set_xbound(year_ended_list[left_yr], year_ended_list[
#plt.ylim((-100,100))
'Normalized income statement data')
plt.title('percent change')
plt.ylabel(#plt.legend()
=(1.6, 1))
plt.legend(bbox_to_anchor
plt.grid()
# space between the plots
#plt.tight_layout(4)
# show plot
plt.show()
Observation
This chart doesn’t provide any useful information, since changes in net income swamp the other parameters. Net income doesn’t trend with revenue over the last five years, neither does EPS.
Normalized consolidated balance sheet
The following chart shows normalized revenue plotted with normalized parameters from the consolidated balance sheet.
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
# set look back range, left_yr is the index into the date range
= -10
left_yr
'FY'][left_yr:],
plt.plot(df_metrics_data['revenue'][left_yr:]-df_dcf_data['revenue'].iloc[left_yr])/np.abs(df_dcf_data['revenue'].iloc[left_yr])*100,
(df_dcf_data['^-',label='Revenue')
'FY'][left_yr:],
plt.plot(df_metrics_data['total_liabilities'][left_yr:]-df_metrics_data['total_liabilities'].iloc[left_yr])/np.abs(df_metrics_data['total_liabilities'].iloc[left_yr])*100,
(df_metrics_data['-.',label='Total liabilities')
'FY'][left_yr:],
plt.plot(df_metrics_data['total_assets'][left_yr:]-df_metrics_data['total_assets'].iloc[left_yr])/np.abs(df_metrics_data['total_assets'].iloc[left_yr])*100,
(df_metrics_data['-.',label='Total assets')
'FY'][left_yr:],
plt.plot(df_metrics_data['total_tangible_assets'][left_yr:]-df_metrics_data['total_tangible_assets'].iloc[left_yr])/np.abs(df_metrics_data['total_tangible_assets'].iloc[left_yr])*100,
(df_metrics_data['-.',label='Total tangible assets')
'FY'][left_yr:],
plt.plot(df_metrics_data['long_term_debt'][left_yr:]-df_dcf_data['long_term_debt'].iloc[left_yr])/np.abs(df_dcf_data['long_term_debt'].iloc[left_yr])*100,
(df_dcf_data['-.',label='Long term debt')
'FY'][left_yr:],
plt.plot(df_metrics_data['current_liabilities'][left_yr:]-df_dcf_data['current_liabilities'].iloc[left_yr])/np.abs(df_dcf_data['current_liabilities'].iloc[left_yr])*100,
(df_dcf_data['-.',label='Current liabilities')
'FY'][left_yr:],
plt.plot(df_metrics_data['depreciation'][left_yr:]-df_dcf_data['depreciation'].iloc[left_yr])/np.abs(df_dcf_data['depreciation'].iloc[left_yr])*100,
(df_dcf_data['-.',label='Depreciation & amortization')
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()# Changes x-axis range
-1])
plt.gca().set_xbound(year_ended_list[left_yr], year_ended_list[
#plt.ylim((0,4))
'Normalized balance statement data')
plt.title('percent change')
plt.ylabel(#plt.legend()
=(1.6, 1))
plt.legend(bbox_to_anchor
plt.grid()
# show plot
plt.show()
Observation
Many balance sheet parameters do not trend with revenue.
Normalized balance statement 5 year look back
# Set the locator
= mdates.YearLocator() # every year
locator = mdates.DateFormatter('%Y')
fmt
# set look back range, left_yr is the index into the date range
= -6
left_yr
'FY'][left_yr:],
plt.plot(df_metrics_data['revenue'][left_yr:]-df_dcf_data['revenue'].iloc[left_yr])/np.abs(df_dcf_data['revenue'].iloc[left_yr])*100,
(df_dcf_data['^-',label='Revenue')
'FY'][left_yr:],
plt.plot(df_metrics_data['total_liabilities'][left_yr:]-df_metrics_data['total_liabilities'].iloc[left_yr])/np.abs(df_metrics_data['total_liabilities'].iloc[left_yr])*100,
(df_metrics_data['-.',label='Total liabilities')
'FY'][left_yr:],
plt.plot(df_metrics_data['total_assets'][left_yr:]-df_metrics_data['total_assets'].iloc[left_yr])/np.abs(df_metrics_data['total_assets'].iloc[left_yr])*100,
(df_metrics_data['-.',label='Total assets')
'FY'][left_yr:],
plt.plot(df_metrics_data['total_tangible_assets'][left_yr:]-df_metrics_data['total_tangible_assets'].iloc[left_yr])/np.abs(df_metrics_data['total_tangible_assets'].iloc[left_yr])*100,
(df_metrics_data['-.',label='Total tangible assets')
'FY'][left_yr:],
plt.plot(df_metrics_data['long_term_debt'][left_yr:]-df_dcf_data['long_term_debt'].iloc[left_yr])/np.abs(df_dcf_data['long_term_debt'].iloc[left_yr])*100,
(df_dcf_data['-.',label='Long term debt')
'FY'][left_yr:],
plt.plot(df_metrics_data['current_liabilities'][left_yr:]-df_dcf_data['current_liabilities'].iloc[left_yr])/np.abs(df_dcf_data['current_liabilities'].iloc[left_yr])*100,
(df_dcf_data['-.',label='Current liabilities')
'FY'][left_yr:],
plt.plot(df_metrics_data['depreciation'][left_yr:]-df_dcf_data['depreciation'].iloc[left_yr])/np.abs(df_dcf_data['depreciation'].iloc[left_yr])*100,
(df_dcf_data['-.',label='Depreciation & amortization')
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()# Changes x-axis range
-1])
plt.gca().set_xbound(year_ended_list[left_yr], year_ended_list[
#plt.ylim((0,4))
'Normalized balance statement data')
plt.title('Percent change')
plt.ylabel(#plt.legend()
=(1.6, 1))
plt.legend(bbox_to_anchor
plt.grid()
# space between the plots
#plt.tight_layout(4)
# show plot
plt.show()
Observation
The plots of relative change of financial statement data versus revenue show that many parameters do not trend with revenue. Trying to figure out why is probably more work than it’s worth, so we will just conclude that the lack of correlation is another reason to avoid this stock.
Market metrics
The share price is determined by the market. The value is determined by the analyst.
One dollar premise
This is a financial test that shows the strength of the business and how well management has rationality allocated to the company’s business.
From a company’s income, subtract all dividends paid to shareholders. What is left over is the company’s retained earnings. Now add the company’s retained earnings over a 10 year period. Next determine the difference between the company’s current market value and its market value 10 years ago. If the business has employed retained earnings unproductively over this ten year period, the market eventually catches up and will set a lower price on the business.
= df_metrics_data['net_income'].sum() - df_metrics_data['dividends'].sum()
retained_earnings print('retained earnings: ${:,.2f}B'.format(retained_earnings/1e9))
retained earnings: $1.69B
Retained earnings are \$1.7B
# Current market value, share price multiplied by number of shares
= df_dcf_data['shares_outstanding'].iloc[-1]*fy_high[-1]
cmv_high = df_dcf_data['shares_outstanding'].iloc[-1]*fy_low[-1]
cmv_low print('Current market value: ${:,.2f}B to ${:,.2f}B'.format(cmv_low/1e9,cmv_high/1e9))
Current market value: $2.04B to $6.06B
# Past market value, share price multiplied by number of shares
= df_dcf_data['shares_outstanding'].iloc[0]*fy_high[0]
pmv_high = df_dcf_data['shares_outstanding'].iloc[0]*fy_low[0]
pmv_low print('Past market value: ${:,.0f}B to ${:,.0f}B'.format(pmv_low/1e9,pmv_high/1e9))
Past market value: $2B to $3B
print('Difference in market value: ${:,.0f}B to ${:,.0f}B'.format((cmv_low-pmv_low)/1e9,(cmv_high-pmv_high)/1e9))
Difference in market value: $-0B to $3B
print('Average difference in market value: ${:,.2f}B'.format(((cmv_low-pmv_low)+(cmv_high-pmv_high))/2/1e9))
Average difference in market value: $1.53B
The difference in market value compared to what it was at the beginning of the evaluation period ranges from \$0 to \$3B. So the HBI was able to take \$1.7B in retained earnings and generate \$0 to \$3B market value. Depending on the time frame, HBI fails the one dollar premise.
Market capitalization
Total value of common equity is calculated using the DCF model from scenario 1 inputs and it is a constant value for the year. The daily market capitalization is calculated from the formula:
\(\text{Market capitalization} = \text{(daily closing share price)} \times \text{(number of shares outstanding)}\)
Market capitalization refers to the total dollar market value of a company’s outstanding shares of stock. It measures the cost of buying all of a company’s shares. Comparing this value to the intrinsic value calculated from the DCF model shows whether the company can be purchased at a discount to its value.
#so = df_dcf_data[‘shares_outstanding’].iloc[-1] # shares outstanding print(‘shares outstanding, basic: {:,.0f}’.format(so))
get starting and ending dates for last calendar year in datetime format
start = year_ended_list[-2] end = start + relativedelta(years=2) p1 = df_price_history.truncate(before=start, after=end)
print total value of common equity for base case and scenario
print(‘total value of common equity, baseline case: ${:,.2f}B’.format(tvce_baseline/1e9)) print(‘total value of common equity, scenario 1: ${:,.2f}B’.format(tvce_S1/1e9)) #print(‘average value of common equity (base & scenario): ${:,.2f}B’.format((tvce_S1+tvce_base)/2/1e9))
make an array
total_value_S1 = np.ones(len(p1))*tvce_S1 # the value is constant across all dates
add scenario 1 total value of common equity data to dataframe
#p1[‘total value avg’] = total_value_avg p1[‘total value S1’] = total_value_S1
start
end
year_ended_list
so
need to get the # of shares for each period, not just use the final share count
so = df_dcf_data[‘shares_outstanding’].iloc[-1] # shares outstanding print(‘shares outstanding, basic: {:,.0f}’.format(so))
df_dcf_data[‘shares_outstanding’]
Set the locator
locator = mdates.MonthLocator() # every month fmt = mdates.DateFormatter(‘%b-%Y’)
plt.plot(p1[‘Close’]so/1e9,label=‘Market capitalization’) plt.plot(p2[‘Close’]so/1e9,label=‘Market capitalization, current year’) #plt.plot(p1[‘total value base’]/1e9,label=‘total value of common equity, base’) plt.plot(p1[‘total value S1’]/1e9,label=‘Total value of common equity, scenario 1’) plt.plot(p1[‘total value S1’]/1e9/0.7,‘-.’,label=‘70% threshold decision model’)
X = plt.gca().xaxis X.set_major_locator(locator) # Specify formatter X.set_major_formatter(fmt) plt.gcf().autofmt_xdate()
#plt.ylim((2,8)) plt.title(‘Market Cap and total value of common equity’) plt.ylabel(‘dollars, $B’) plt.legend(bbox_to_anchor=(1.1, 1)) #plt.legend() plt.grid()
show plot
plt.show()
Plotting year of last 10K and current year stock prices
making changes to plot TVCE only for most recient 10K
print('shares outstanding, basic: {:,.0f}'.format(so))
# print total value of common equity for base case and scenario
print('total value of common equity, baseline case: ${:,.2f}B'.format(tvce_baseline/1e9))
print('total value of common equity, scenario 1: ${:,.2f}B'.format(tvce_S1/1e9))
shares outstanding, basic: 349,361,517
total value of common equity, baseline case: $2.67B
total value of common equity, scenario 1: $2.98B
Make a new data frame for price history covering year of 10K upto most recient date in saved price history. That is, last FY year and current year.
# get starting and ending dates for last calendar year in datetime format
= year_ended_list[-1]
start #end = start + relativedelta(years=2)
= df_price_history.truncate(before=start) p1
Make a new data frame for price history covering only the time period of most recient 10K
= start + relativedelta(years=1)
end = df_price_history.truncate(before=start,after=end) p2
# make an array
= np.ones(len(p2))*tvce_S1 # the value is constant across all dates
total_value_S1
# add scenario 1 total value of common equity data to dataframe
'total value S1'] = total_value_S1 p2[
# Set the locator
= mdates.MonthLocator() # every year
locator = mdates.DateFormatter('%b-%Y')
fmt
'Close']*so/1e9,label='Market capitalization')
plt.plot(p1[#plt.plot(p2['Close']*so/1e9,label='Market capitalization, current year')
#plt.plot(p1['total value base']/1e9,label='total value of common equity, base')
'total value S1']/1e9,label='Total value of common equity, scenario 1')
plt.plot(p2[#plt.plot(p1['total value S1']/1e9/0.7,'-.',label='70% threshold decision model')
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
1,6))
plt.ylim(('Market Cap and total value of common equity')
plt.title('dollars, $B')
plt.ylabel(=(1.1, 1))
plt.legend(bbox_to_anchor#plt.legend()
plt.grid()
# show plot
plt.show()
Need a write up for this graph.
#so = df_dcf_data['shares_outstanding'].iloc[-1] # shares outstanding
print('shares outstanding, basic: {:,.0f}'.format(so))
# get starting and ending dates for last calendar year in datetime format
= year_ended_list[-1]
start #end = start + relativedelta(years=2)
= df_price_history.truncate(before=start)
p1
# print total value of common equity for base case and scenario
print('total value of common equity, baseline case: ${:,.2f}B'.format(tvce_baseline/1e9))
print('total value of common equity, scenario 1: ${:,.2f}B'.format(tvce_S1/1e9))
#print('average value of common equity (base & scenario): ${:,.2f}B'.format((tvce_S1+tvce_base)/2/1e9))
# make an array
= np.ones(len(p1))*tvce_S1 # the value is constant across all dates
total_value_S1
# add scenario 1 total value of common equity data to dataframe
#p1['total value avg'] = total_value_avg
'total value S1'] = total_value_S1 p1[
shares outstanding, basic: 349,361,517
total value of common equity, baseline case: $2.67B
total value of common equity, scenario 1: $2.98B
'Close'] p1[
datetime
2022-01-03 16.920000
2022-01-04 17.360001
2022-01-05 16.940001
2022-01-06 17.030001
2022-01-07 16.860001
...
2023-03-06 5.610000
2023-03-07 5.480000
2023-03-08 5.490000
2023-03-09 5.350000
2023-03-10 5.100000
Name: Close, Length: 298, dtype: float64
p1
Date | Open | High | Low | Close | Adj Close | Volume | total value S1 | |
---|---|---|---|---|---|---|---|---|
datetime | ||||||||
2022-01-03 | 2022-01-03 | 16.879999 | 16.990000 | 16.770000 | 16.920000 | 15.939794 | 3148900 | 2.980053e+09 |
2022-01-04 | 2022-01-04 | 17.139999 | 17.490000 | 17.080000 | 17.360001 | 16.354307 | 3454900 | 2.980053e+09 |
2022-01-05 | 2022-01-05 | 17.400000 | 17.549999 | 16.930000 | 16.940001 | 15.958636 | 3945900 | 2.980053e+09 |
2022-01-06 | 2022-01-06 | 17.080000 | 17.240000 | 16.850000 | 17.030001 | 16.043425 | 3738800 | 2.980053e+09 |
2022-01-07 | 2022-01-07 | 16.809999 | 17.010000 | 16.549999 | 16.860001 | 15.883271 | 3743100 | 2.980053e+09 |
... | ... | ... | ... | ... | ... | ... | ... | ... |
2023-03-06 | 2023-03-06 | 5.900000 | 5.960000 | 5.600000 | 5.610000 | 5.610000 | 16682300 | 2.980053e+09 |
2023-03-07 | 2023-03-07 | 5.620000 | 5.700000 | 5.430000 | 5.480000 | 5.480000 | 10891900 | 2.980053e+09 |
2023-03-08 | 2023-03-08 | 5.490000 | 5.570000 | 5.430000 | 5.490000 | 5.490000 | 9305200 | 2.980053e+09 |
2023-03-09 | 2023-03-09 | 5.480000 | 5.620000 | 5.340000 | 5.350000 | 5.350000 | 11794000 | 2.980053e+09 |
2023-03-10 | 2023-03-10 | 5.310000 | 5.350000 | 5.070000 | 5.100000 | 5.100000 | 13896500 | 2.980053e+09 |
298 rows × 8 columns
= start + relativedelta(years=1)
end = df_price_history.truncate(before=start,after=end) p2
p2
Date | Open | High | Low | Close | Adj Close | Volume | |
---|---|---|---|---|---|---|---|
datetime | |||||||
2022-01-03 | 2022-01-03 | 16.879999 | 16.990000 | 16.770000 | 16.920000 | 15.939794 | 3148900 |
2022-01-04 | 2022-01-04 | 17.139999 | 17.490000 | 17.080000 | 17.360001 | 16.354307 | 3454900 |
2022-01-05 | 2022-01-05 | 17.400000 | 17.549999 | 16.930000 | 16.940001 | 15.958636 | 3945900 |
2022-01-06 | 2022-01-06 | 17.080000 | 17.240000 | 16.850000 | 17.030001 | 16.043425 | 3738800 |
2022-01-07 | 2022-01-07 | 16.809999 | 17.010000 | 16.549999 | 16.860001 | 15.883271 | 3743100 |
... | ... | ... | ... | ... | ... | ... | ... |
2022-12-23 | 2022-12-23 | 5.920000 | 6.110000 | 5.860000 | 6.100000 | 6.100000 | 8091400 |
2022-12-27 | 2022-12-27 | 6.080000 | 6.330000 | 6.050000 | 6.230000 | 6.230000 | 8530700 |
2022-12-28 | 2022-12-28 | 6.240000 | 6.280000 | 5.990000 | 6.060000 | 6.060000 | 7358500 |
2022-12-29 | 2022-12-29 | 6.140000 | 6.340000 | 6.130000 | 6.260000 | 6.260000 | 7770400 |
2022-12-30 | 2022-12-30 | 6.170000 | 6.400000 | 6.160000 | 6.360000 | 6.360000 | 7638300 |
251 rows × 7 columns
'Close'] p2[
datetime
2022-01-03 16.920000
2022-01-04 17.360001
2022-01-05 16.940001
2022-01-06 17.030001
2022-01-07 16.860001
...
2022-12-23 6.100000
2022-12-27 6.230000
2022-12-28 6.060000
2022-12-29 6.260000
2022-12-30 6.360000
Name: Close, Length: 251, dtype: float64
'total value S1'] p1[
datetime
2022-01-03 2.980053e+09
2022-01-04 2.980053e+09
2022-01-05 2.980053e+09
2022-01-06 2.980053e+09
2022-01-07 2.980053e+09
...
2023-03-06 2.980053e+09
2023-03-07 2.980053e+09
2023-03-08 2.980053e+09
2023-03-09 2.980053e+09
2023-03-10 2.980053e+09
Name: total value S1, Length: 298, dtype: float64
# Set the locator
= mdates.MonthLocator() # every year
locator = mdates.DateFormatter('%b-%Y')
fmt
'Close']*so/1e9,label='Market capitalization')
plt.plot(p1[#plt.plot(p2['Close']*so/1e9,label='Market capitalization, current year')
#plt.plot(p1['total value base']/1e9,label='total value of common equity, base')
'total value S1']/1e9,label='Total value of common equity, scenario 1')
plt.plot(p1['total value S1']/1e9/0.7,'-.',label='70% threshold decision model')
plt.plot(p1[
= plt.gca().xaxis
X
X.set_major_locator(locator)# Specify formatter
X.set_major_formatter(fmt)
plt.gcf().autofmt_xdate()
1,6))
plt.ylim(('Market Cap and total value of common equity')
plt.title('dollars, $B')
plt.ylabel(=(1.1, 1))
plt.legend(bbox_to_anchor#plt.legend()
plt.grid()
# show plot
plt.show()
As shown in the plot above, the market capitalization of HBI has steadily fallen over the past year, to the point where the market capitalization is less than the total value of common equity as calculated by DCF model scenario 1. By some measures, HBI is a value stock. Since the stock was purchased as a dividend paying stock, it doesn’t make sense to continue to hold the stock.
so
csp
so*csp/1e9
print(‘Current market capitalization: ${:.2f}B’.format(so*csp/1e9))
df_price_history
year_ended_list[-1]
p2 = df_price_history.truncate(before=year_ended_list[-1])
p2
#column names: fiscal years years_list = df_metrics_sheet.columns[1:].values.astype(‘str’)[::-1]
convert years to datetime format
year_ended_list = [] for i in years_list: year_ended_list.append(datetime.strptime(i, ‘%Y’))
make empty lists to store open, close, average close, high and low price data for each fiscal year
fy_open = [] fy_close = [] fy_avg_close = [] fy_high = [] fy_low = []
for i in year_ended_list: start = i end = i + relativedelta(years=1) p1 = df_price_history.truncate(before=start, after=end) if len(p1) == 0: fy_open.append(np.nan) fy_close.append(np.nan) fy_avg_close.append(np.nan) fy_high.append(np.nan) fy_low.append(np.nan) else: fy_open.append(p1[‘Open’].iloc[0]) fy_close.append(p1[‘Close’].iloc[-1]) fy_avg_close.append(p1[‘Close’].mean()) # could aslo use median fy_high.append(p1[‘Close’].max()) fy_low.append(p1[‘Close’].min())
convert from list to numpy array
fy_open = np.asarray(fy_open) fy_close = np.asarray(fy_close) fy_avg_close = np.asarray(fy_avg_close) fy_high = np.asarray(fy_high) fy_low = np.asarray(fy_low)
Qualitative metrics
Beyond the numbers in the financial statements, there are metrics that are qualitative in nature that are important to the investor. These are subjective measures of business and management operations that influence value. In this section a few qualitative metrics are discussed below.
\(\Large {\color {red} {\text {This section needs an update, remove BMI narrative}}}\)
Simple and understandable business model
BMY is a pharmaceutical company that manufactures drugs in several therapeutic areas. Although the science is not simple, the business framework of R&D, patent protection, manufacturing and distribution is typical of other manufacturing firms operating in the technology sector.Favorable long term prospects
The company has a long history and the recent trends are favorable, except for the acquisition in 2019, which upset the trends.Commodity reliance
By commodity is meant a product or service that is easily reproducible by a competitor. Pharmaceuticals are the result of R&D and protected by patents. The barrier to entry is high for Pharmaceutical companies.Consistent operating history
The trends for RoE, RoA and profit margin have been plotted above. The effect of the acquisition of Celgene has caused these ratios to go negative in 2020. From 2016 to 2019, these ratios had wide variation year to year, with 2017 showing a decline followed by a large increase the following year. Normally steady performance is better than the erratic variation shown here. (LT debt)/Equity and (total liabilities)/Equity have been steady and below 2. (total liabilities)/NOP have been erratic over the evaluation period.Rationality
Do comments and discussion made by the management in the annual reports reflect an optimal level of benefit or utility to the company over the long term?- Focus on core aspects
The company operates in one segment engaged in the discovery, development, licensing, manufacturing, marketing, distribution and sale of biopharmaceutical products on a global basis.
- Only invest in high ROE businesses
The principal strategy is to combine the resources, scale and capability of a pharmaceutical company with the speed and focus on innovation of the biotech industry. The acquisitions of Celgene in 2019 and MyoKardia in 2020 will further position us as a leading biopharmaceutical company, expanding our oncology, hematology, immunology and cardiovascular portfolios with several near-term assets and additional external partnerships. - Focus on shareholder equity
Adding value to the company The priorities are to continue to renew and diversify our portfolio through launching our new product portfolio, advancing our early, mid and late-stage pipeline, and executing disciplined business development. They remain committed to reducing our debt and returning capital to shareholders.
- Focus on core aspects
Back to Contents
9) Decision model
The decision model establishes thresholds that are to used in the purchase decision. There are three hard decision thresholds in this model which are:
1. Intrinic value
2. Debt
3. Dividend payout ratio
4. Dividend IIR
5. NACI managemet evaluation
6. One dollar premise
\(\Large {\color {red} {\text {update template}}}\)
The first threshold is based on the intrinisic value of the company as calculated by the DCF model semario 1. Reconizing that absolute intrinsic value is an elusive concept, judgement, justified by facts (assets, earnings, dividends, debt and cash flow), establishes the value by adjusting various rates, based on judgement and using a five year forward projection period. This should give a intrinsic value that is based on the historical data, modified by judgement.
I’m using a threshold of the intrinsic value calculated in senario 1 (isv_S1) that is greater than 70% of the current stock price, provided that the NAIC valuation is above the current stock price. This accounts for the inadequacy or incorrectness of the data, the uncertainties of the future, and considers the behavior of the market.
The second threshold is the level of debt. The ratios of (LT debt)/Equity, (total liabilities)/Equity and (total liabilities)/NOP are ploted for the evaluation period. Over the evaluation period the (LT debt)/Equity and (total liabilities)/Equity should be less than 2 and stable. A threshold of 2 has been discussed in the litureture as a level of debt that a company can reasonably take on.
The thereshold for (total liabilities)/NOP is set at 10. This means that the company can pay off all the liabilities with tens years worth of NOP, which seems like a reasonable timeframe for an established and stable company.
The third threshold is the dividend payout ratio and is a relative measure of how much the company is paying to shareholders in dividends compared to the metrics of NOP and free cash flow (Net cash provided by operating activities). The payout ratio is useful for assessing a dividend’s sustainability. Payout ratio for a REIT is established by tax law and not used as an evaluation criteria. For other industries a threshold of 50% has been set as the limit.
The dividend IRR threshold is the internal rate of return for investor dividend cash flow (divident_irr) should be greater than 10 year treasury bond yield (tby) plus the equity risk premium (eq_rp). Otherwise, other investment operatunities should be looked at.
In the decision model there are soft thresholds based on judgement. Soft thresholds are a collection of ratios and analysis that taken together tell a story of the performance of the conmpany and manatgments ability to run the company and support dividends over the long term. Use judgement and make an evalaution.
The third critiera is a collection of ratios and analysis that taken together tell a story of the performance of the conmpany and manatgments ability to run the company and support dividends over the long term. Use judgement and make an evalaution. These are the following:
1. Financial metrics
2. Market metrics
3. Qualitative metrics
The soft thresholds are discused in section 10.
Check DCF and NAIC value thresholds
# check DCF senario 1
= isv_S1/csp #ratio of isv to csp
dcf_score = 0.7
dcf_threshold if dcf_score < 0.7:
print('FAIL, DCF score is less than {:.1f} at {:.1f}'.format(dcf_threshold,dcf_score))
else:
print('PASS, DCF score is above {:.1f} at {:.1f}'.format(dcf_threshold,dcf_score))
# check NAIC
= np.array([naic_price_eps_low,naic_price_pm_low]).min()/csp
naic_score = 1
naic_threshold if naic_score < 1:
print('FAIL, NAIC score is less than {:.1f} at {:.1f}'.format(naic_threshold,naic_score))
else:
print('PASS, NAIC score is above {:.1f} at {:.1f}'.format(naic_threshold,naic_score))
# check both scores
if naic_score < 1 or dcf_score < 0.7:
print('One or both DCF and NAIC scores failed')
else:
print('Both DCF and NAIC scores pass')
PASS, DCF score is above 0.7 at 1.9
FAIL, NAIC score is less than 1.0 at 0.9
One or both DCF and NAIC scores failed
Check debt thresholds
= 4
debt_lookback = df_dcf_data['long_term_debt'][-debt_lookback:].mean()/df_metrics_data['shareholder_equity'][-debt_lookback:].mean()
avg_LT_debt2EQ = df_metrics_data['total_liabilities'][-debt_lookback:].mean()/df_metrics_data['shareholder_equity'][-debt_lookback:].mean()
avg_TLiability2EQ = df_metrics_data['total_liabilities'][-debt_lookback:].mean()/nop[-debt_lookback:].mean()
avg_TLiability2NOP
print('long term debt to shareholder equity ratio = {:.2f}'.format(avg_LT_debt2EQ))
print('total liabilities to shareholder equity ratio = {:.2f}'.format(avg_TLiability2EQ))
print('total liabilities to NOP ratio = {:.2f}'.format(avg_TLiability2NOP))
if (avg_LT_debt2EQ > 2) or (avg_TLiability2EQ > 2) or (avg_TLiability2NOP > 10):
print('FAILED one of the debt threshold limits')
long term debt to shareholder equity ratio = 4.42
total liabilities to shareholder equity ratio = 8.08
total liabilities to NOP ratio = 11.51
FAILED one of the debt threshold limits
Check dividend payout and IIR thresholds
\(\Large {\color {red} {\text {update comments about IIR}}}\)
# check dividend payout ratio average the last three years
print('Dividends are paid at {:.1f}% of cash flow'.format(
'dividends']/df_metrics_data['free_cash_flow'])[-3:].mean()*100))
(df_metrics_data[print('Dividends are paid at {:.1f}% of NOP'.format((df_metrics_data['dividends']/nop)[-3:].mean()*100))
if ((df_metrics_data['dividends']/nop)[-3:].mean() or (df_metrics_data['dividends']/df_metrics_data['free_cash_flow'])[-3:].mean()) > 0.5:
print('FAIL, dividend payout ration too high')
Dividends are paid at 7.4% of cash flow
Dividends are paid at 1100.9% of NOP
FAIL, dividend payout ration too high
# Check dividend IRR limit
if dividend_irr < (tby+eq_rp):
print('FAIL, dividend IRR is less than {:.2f} at {:.2f}'.format((tby+eq_rp)*100,dividend_irr*100))
else:
print('PASS, dividend IRR is above {:.2f} at {:.2f}'.format((tby+eq_rp)*100,dividend_irr*100))
FAIL, dividend IRR is less than 6.48 at 4.41
# check DCF senario 1
= isv_S1/csp #ratio of isv to csp
dcf_score = 0.7
dcf_threshold if dcf_score < 0.7:
print('FAIL, DCF score is less than {:.1f} at {:.1f}'.format(dcf_threshold,dcf_score))
else:
print('PASS, DCF score is above {:.1f} at {:.1f}'.format(dcf_threshold,dcf_score))
# check NAIC
= np.array([naic_price_eps_low,naic_price_pm_low]).min()/csp
naic_score = 1
naic_threshold if naic_score < 1:
print('FAIL, NAIC score is less than {:.1f} at {:.1f}'.format(naic_threshold,naic_score))
else:
print('PASS, NAIC score is above {:.1f} at {:.1f}'.format(naic_threshold,naic_score))
# check both scores
if naic_score < 1 or dcf_score < 0.7:
print('One or both DCF and NAIC scores failed')
else:
print('Both DCF and NAIC scores pass')
PASS, DCF score is above 0.7 at 1.9
FAIL, NAIC score is less than 1.0 at 0.9
One or both DCF and NAIC scores failed
comments:
- NACI managemet evaluation
# check profit margin trends
if pm_trend < 0:
print('FAIL, profit margin trend over the evaluation period is negative at {:.1f}%'.format(pm_trend*100))
else:
print('PASS, profit margin trend over the evaluation period is positive at {:.1f}%'.format(pm_trend*100))
if pm1_trend < 0:
print('FAIL, profit margin trend over the last {:.0f} years is negative at {:.1f}%'.format(-left_yr,pm1_trend*100))
else:
print('PASS, profit margin trend over the last {:.0f} years is positive at {:.1f}%'.format(-left_yr,pm1_trend*100))
FAIL, profit margin trend over the evaluation period is negative at -0.5%
FAIL, profit margin trend over the last 6 years is negative at -1.3%
Checking trends based on EPS and NOP.
# check yield trend based on EPS
if pm_trend < 0:
print('FAIL, EPS yield trend over the evaluation period is negative at {:.1f}%'.format(y1_trend*100))
else:
print('PASS, EPS yield trend over the evaluation period is positive at {:.1f}%'.format(y1_trend*100))
if pm1_trend < 0:
print('FAIL, EPS yield trend over the last {:.0f} years is negative at {:.1f}%'.format(-left_yr,y1a_trend*100))
else:
print('PASS, EPS yield trend over the last {:.0f} years is positive at {:.1f}%'.format(-left_yr,y1a_trend*100))
FAIL, EPS yield trend over the evaluation period is negative at -0.7%
FAIL, EPS yield trend over the last 6 years is negative at -1.5%
# check yield trend based on NOP
if pm_trend < 0:
print('FAIL, NOP yield trend over the evaluation period is negative at {:.1f}%'.format(y2_trend*100))
else:
print('PASS, NOP yield trend over the evaluation period is positive at {:.1f}%'.format(y2_trend*100))
if pm1_trend < 0:
print('FAIL, NOP yield trend over the last {:.0f} years is negative at {:.1f}%'.format(-left_yr,y2a_trend*100))
else:
print('PASS, NOP yield trend over the last {:.0f} years is positive at {:.1f}%'.format(-left_yr,y2a_trend*100))
FAIL, NOP yield trend over the evaluation period is negative at -0.3%
FAIL, NOP yield trend over the last 6 years is negative at -0.2%
- One dollar premise
retained_earnings = df_metrics_data[‘net_income’].sum() - df_metrics_data[‘dividends’].sum()
print(‘retained earnings: ${:,.2f}B’.format(retained_earnings/1e9))
retained earnings: $1.69B
Retained earnings are $1.7B